Row Number in Symfony Doctrine Query - php

I am storing data for lap times in a database, the data consists of a distance, time, average speed and max speed.
I am trying to display a leaderboard which shows the top ten people in whatever query you set (who has gone thr furthest in total, best average time etc). However, below the top ten I want to show the user who is logged ins position in the leaderboard. To do this I am trying to run the same query ordering my results and adding a ROW NUMBER to get the position.
I am using symfony 1.4 with the Doctrine ORM and I can't for the life of me figure out how to get row numbers in a query. I know you can do it in SQL like so:
SELECT full_name, ROW_NUMBER() OVER(ORDER BY distance) AS row_number
Yet I can't get it working in Doctrine Symfony.
Does anyone have any ideas on a way I can do this? (or even another way of going about it)
Thanks in advance.

Ok heres my solution:
I kind of found an answer to this after some more experimenting and collaborating.
What I did was get rid of the select and just return the ordered list of results;
$results = self::getInstance()->createQuery('r')
->orderBy('r.distance')
->execute();
Then I hydrated this result into an array and used array_search() to find the key of the result in the array (luckily I am returning user data here, and I know the user I am looking for in the array)
$index = array_search($user->toArray(), $results->toArray());
I can then return the $index + 1 to give me the users position in the leaderboard.
There is probably a better way to do this database side, but I couldn't for the life of me find out how.
If anyone has a better solution then please share.

Related

performance issue from 5 queries in one page

As i am a junior PHP Developer growing day by day stuck in a performance problem described here:
I am making a search engine in PHP ,my database has one table with 41 column and million's of rows obviously it is a very large dataset. In index.php i have a form for searching data.When user enters search keyword and hit submit the action is on search.php with results.The query is like this.
SELECT * FROM TABLE WHERE product_description LIKE '%mobile%' ORDER BY id ASC LIMIT 10
This is the first query.After result shows i have to run 4 other query like this:
SELECT DISTINCT(weight_u) as weight from TABLE WHERE product_description LIKE '%mobile%'
SELECT DISTINCT(country_unit) as country_unit from TABLE WHERE product_description LIKE '%mobile%'
SELECT DISTINCT(country) as country from TABLE WHERE product_description LIKE '%mobile%'
SELECT DISTINCT(hs_code) as hscode from TABLE WHERE product_description LIKE '%mobile%'
These queries are for FILTERS ,the problem is this when i submit search button ,all queries are running simultaneously at the cost of Performance issue,its very slow.
Is there any other method to fetch weight,country,country_unit,hs_code speeder or how can achieve it.
The same functionality is implemented here,Where the filter bar comes after table is filled with data,How i can achieve it .Please help
Full Functionality implemented here.
I have tried to explain my full problem ,if there is any mistake please let me know i will improve the question,i am also new to stackoverflow.
Firstly - are you sure this code is working as you expect it? The first query retrieves 10 records matching your search term. Those records might have duplicate weight_u, country_unit, country or hs_code values, so when you then execute the next 4 queries for your filter, it's entirely possible that you will get values back which are not in the first query, so the filter might not make sense.
if that's true, I would create the filter values in your client code (PHP)- finding the unique values in 10 records is going to be quick and easy, and reduces the number of database round trips.
Finally, the biggest improvement you can make is to use MySQL's fulltext searching features. The reason your app is slow is because your search terms cannot use an index - you're wild-carding the start as well as the end. It's like searching the phonebook for people whose name contains "ishra" - you have to look at every record to check for a match. Fulltext search indexes are designed for this - they also help with fuzzy matching.
I'll give you some tips that will show useful in many situations when querying a large dataset, or mostly any dataset.
If you can list the fields you want instead of querying for '*' is a better practice. The weight of this increases as you have more columns and more rows.
Always try to use the PK's to look for the data. The more specific the filter, the less it will cost.
An index in this kind of situation would come pretty handy, as it will make the search more agile.
LIKE queries are generally pretty slow and resource heavy, and more in your situation. So again, the more specific you are, the better it will get.
Also add, that if you just want to retrieve data from this tables again and again, maybe a VIEW would fit nicely.
Those are just some tips that came to my mind to ease your problem.
Hope it helps.

MySQL Performance for Online Games Highscore Lists

I have a question about making "Highscore-Lists".
Lets say I have an online game with 1.000.000 active users. Each user has points from 0 to X. Now, I want to show a ranking-list. It would be insane to show all million entries in one page so it is divided into Y pages (100 entries each page => 10.000 pages).
I am not really sure how to solve it.
1. The easiest way to do that would be loading all 1m entries
in one SELECT, get the result and find current user with a for loop and show that specific page. (but all other 999.900 entries will be saved in RAM eventhough its not showing up). For a page change I could just use the result data with no second database call. (So I don't care about point changes during that time)
SELECT UserName, UserID, Points FROM UserAccount ORDER BY Points;
2. My second idea was, to load each page individually but than I do not know
2.1 if it is really better performance
2.2 how to get the right start page because I only have the points of the user but not really his place
So how could I solve that problem. I dont really know what mysql can handle. Are more small calls better then one huge call.
Can I even save huge result data?
Second solution would update all changed points with each page change, though but i care more about performance then always uptodate list-data.
Thank you for your help!
Markus
Use pagination. In SQL it's a "limit" clause:
SELECT UserName, UserID, Points FROM UserAccount ORDER BY Points LIMIT 0, 20;
The above query will return only the first 20 rows of the original selection.
You can pass page parameters via get, like this: highscore.php?page=1 or ?page=2 and so on.

Ranking in Symfony/Doctrine

I have 3 entities in Symfony. Candidate, School, Game a candidate is assigned to one school and can start games. The games entity contains the score (of that) game. So far so good, here comes the tricky part:
I have to display to the candidates, what rank they have currently, as well as the top 10 players.
I know, I could use a native query for mysql and do something like proposed here: https://stackoverflow.com/a/3333697/2989952
But then, to get the rank of the candidate I'd have to load all entries from the db and loop throu them in PHP (or with Doctrines Criteria). Is there a better way to get the rank? I could also add a column point's or something in the candidate entity and update that after every game and then just sort by that column, still I'd have to loop throu all entries again in PHP.
Thanks for your help.
For the second part 'How to rank top 10 players' i would use index from loop with this query.
$gameRepository->findBy([],['score'=>'desc'],10);
For the first part.This looks promising and can be transfered into DQL easily.

php - How to reverse a math equation based on a condition?

I have a unique and specific situation.
I have a search that searches volleyball players' stats. Once it queries and gets all the data, it then runs this:
$priority_query = $wpdb->get_results("
SELECT MAX(CAST(value AS UNSIGNED))
FROM wp_bp_xprofile_data
WHERE field_id = $field->id
", ARRAY_N);
$field_max = $priority_query[0][0];
$priority_percentage = $field->priority / $priority_total;
$priority_rank = $priority_rank + round($priority_percentage * ($value_total/$field_max), 3);
}
$priority_rank = $priority_rank * 10;
That is to figure out the players ranking based of off the other players that are returned by the search. It works great. However, it essentially is all based on "bigger is better". So it gives a higher rank for height, jumping height. Stuff like that.
Now I've added two more search criteria that are based on speed (sprints). It's giving a higher rank to the slowest people because it's a greater number. I need it to be opposite (smaller is better) when one of the new fields is selected for the search.
I've tried all sorts of things, but can't figure it out. I tried changing the query from MAX to MIN, but the rankings went through the roof and were still showing the slowest as the best.
Does anybody know how I could do this? Any help would be greatly appreciated, this has been driving me crazy.
Thank you
EDIT:
I can't have negative numbers since the ranking it being displayed. Also, I can't have any static numbers since players can sign up whenever they want and add their stats which in turn modifies the search results.
A co-worker and I got it working just by switching thes around: $value_total/$field_max to $field_max/$value_total and SELECT MAX to SELECT MIN Then I added a conditional statement to figure it out properly.
A slight issue however is when you start mixing the two types of criteria together. It gets a little wonky, but still ranks in the proper order.

Retrieve the mean of results from imputed data PHP/MySQL

First of, I'm pretty new to this site and coding in general so please explain in simple terms as I'm still learning! Thanks
Ok, so I've got a database of results. These are 1-6 ratings. I've already created the ability to retrieve certain results (user, group, all).
But now I'm wanting to alongside retrieving the group and all results to display at the top of the results a mean for each question.
So to start I'm wanting something like this I believe.
SELECT sum(r1), sum(r2), sum(r3) so on,
FROM table
This is where I get confused.
I think I'd need a variable to contain these and then another that counts the amount of entries to divide the total of r1 hence the mean.
Any ideas?..
To calculate a mean, use the AVG function, e.g.
SELECT AVG(r1), AVG(r2)
FROM table
See the MySQL docs.

Categories