MySQL Fetch highest value by key and then add rank to it - mysql

I'm trying to create a mysql query that looks through my scoreboard for a given playerid and then finds their highest score and then adding a rank to that score.
I've come quite close to what I'm trying to achieve with this code:
SELECT PlayerUUID, `iGamescore` as score, FIND_IN_SET( iGamescore, (
SELECT GROUP_CONCAT( iGamescore
ORDER BY iGamescore ASC )
FROM crystm_gameScoreboard )
) AS rank
FROM crystm_gameScoreboard
WHERE PlayerUUID = '4c8984f3-651a-48bc-ad1a-879624380fab'
LIMIT 1
Returns:
But I do know that this player has played multiple times and is therefore multiple times in the scoreboard. As seen here:
So the issue here is that yes, it does find the player and gives the rank correctly.. However, since it exists multiple times, it saves the very first score instead of the highest score. How would I fix my query to correct for this or would you instead of creating a new score every time they create a highscore for themselves, just update their previous record in the scoreboard?
Thanks in advance

To get the highest score you need a GROUP BY:
SELECT
PlayerUUID,
MAX(`iGamescore`) as score
RANK() OVER (ORDER BY MAX(`iGamescore`) DESC) as Rang
FROM crystm_gameScoreboard
GROUP BY PlayerUUID
ORDER BY 3 ASC
The order by 3 ASC makes the list sorted by rank

This post solved it:
MySQL - Rank user amongst list of top high-scores
Had everything I was looking for. I dont know why I could not find this post but when searching, keywords are important haha.
Thanks for inputs tho.

Related

Get row rank without fetching every row

I'm using this query to fetch a highscore of a certain user.
SELECT score FROM highscores WHERE user_id=?
I would like to know the how-many'th this particular highscore is compared to the other scores. So basically the row number after we DESC ordered the highscores table.
I could of course fetch all rows and look at the array key but I was wondering if there's a more performance friendly method directly via the MySQL query. The highscore table contains around 500k rows, and it seems a bit overkill (and it will take some time) to have to fetch them all first just to get the rank number of the user's score.
Some time ago I helped a friend with a similar task, and wrote an article,
How to get a single player's rank based on the score.
So the idea is to run a count(*) query with a WHERE clause to include all players having a higher score:
SELECT count(*)+1 FROM players WHERE score > ?
or, based on the user id,
SELECT count(*)+1 FROM players WHERE score > (SELECT score FROM players WHERE id = ?)
This solution is much simpler than anything I was able to find on Stack Overflow.
It can be also refined, to take into account other fields, in case two users have the same score, such as time when the score has been updated:
SELECT count(*)+1 FROM players WHERE score > ? OR (score = ? AND score_updated < ?)

MySQL user rank with sorted results

I have the following mysql statement to bring back top 10 user data plus the data for the signed-in user (if the signed-in user is in the top 10 there'll only be 10 results total, otherwise there's 11)...
(SELECT user_id, points, amountLikes, amountComments
FROM all_scores_table
ORDER BY points desc, amountLikes desc, amountComments desc
LIMIT 0,10)
UNION
(SELECT user_id, points, amountLikes, amountComments
FROM all_scores_table
WHERE user_id = $session_user_id)
ORDER BY points desc, amountLikes desc, amountComments desc
The all_scores_table has exactly 1 row per user. I'm now trying to add rank information to the second query (e.g. if there's 11 rows, I want to know whether the session_user_id is 11th or 468th in the list).
I've read a bunch of similar posts but couldn't find an answer that seemed to apply to the way I've written my initial query by unioning sorted results - e.g. I can't just add a simple count of rows with points greater than my user, because if they're even I want to reference amountLikes, amountComments to find the true order.
I could of course do this in PHP with a second query, but am hoping someone notices an elegant way to achieve this in mysql alone
I would recommend not trying to be clever and use one query. Instead, just make two queries, one which finds the top ten and the other which finds the logged in user along with his numerical rank. For the first query, you can use what you already have:
SELECT
user_id, points, amountLikes, amountComments
FROM all_scores_table
ORDER BY points DESC, amountLikes DESC, amountComments DESC
LIMIT 10
As for assigning ranks, you can easily handle this in your PHP code when you are iterating over the result set. Just use a variable counter starting at 1.
To get the rank of the currently logged in user, it will take more work, because he could be buried in the midst of hundreds (or more) of records. One option is to use session variables:
SET #row_number = 0;
SELECT
(#row_number:=#row_number + 1) AS rank,
user_id, points, amountLikes, amountComments
FROM all_scores_table
WHERE user_id = $session_user_id
ORDER BY points DESC, amountLikes DESC, amountComments DESC
This second query should return a single record (assuming each user appears only once), containing the metadata you need along with a numerical rank.
In your PHP logic, you can check if the rank be in the top ten, and, if so, not display this extra single record on the bottom of your table.

If statement in SQL

I have a game, and a MySQL database table where I store the results of users. Every result is stored, but on highscore page I show only the best result from a certain user, like this:
SELECT user_id,MAX(score) as score
FROM table
GROUP BY user_id
ORDER BY score DESC LIMIT $startLimit,$numPerPage
But now I also want to make it relate to time it took for player to reach certain score, if the scores are level.
For example if the player has two same scores, I want to grab the one that took him less time (ofcourse there is a column "time" in this table).
Try this:
SELECT user_id,score,MIN(time) as MinTime
FROM
(SELECT user_id,MAX(score) as score,time
FROM table
GROUP BY user_id, time ) T
GROUP BY user_id,score
ORDER BY score DESC
LIMIT $startLimit,$numPerPage
It will return the records with minimum time if the user has same score.

Order by most searched words in MYSQL

I've designed a simple website which enables users to search on a MYSQL database. The search method is also simple: the user types a word in a textfield and it searches in the database.
Now i want to include in this website a table with the most searched words and i didn't find anything until now but this sentence:
select distinct column
, count(1) as total
from dept
group by column
order by total desc
limit 5
but this doesnt retrieve what i want. Do you have any idea of how I get this result?
Thank you in advance!
A simple example for a small site:
After each search, add a row to a table searched. Bonus points for adding a timestamp.
insert into searched (keyword, timestamp) values ('foo', 1234567890);
From there:
select keyword, count(*) as total from searched
group by keyword order by total desc limit 5;
Of course, for simple things like this, I'd use redis.

How to order a sql query for a ranking system with both average and number of votes?

I'm creating a list for best movies which are based on the users votes like imdb. I have done the list with this sql query:
SELECT data_id, COUNT(point), SUM(point)
FROM voting_table
WHERE data_type='1'
GROUP BY data_id
order by SUM(point)/COUNT(point)
DESC limit 100
This works well but i want also the number of votes(point) affect the order. I mean if a movie gets average of 8 with 10 votes and another movie gets average of 8 but with 5 votes. The one which has more votes should be listed higher than the other one. How can i do it? And is the query i wrote is efficent for server performance?
There is function AGV, I suggest you use that.
sort by avg, then by count or sum
...
ORDER BY AVG(point) DESC, COUNT(point) DESC
...
As of performance, there is not much you can do wihout complicating data structure.
It should be fine as it is unless your site si going to be as popular as imdb.
If your voting table grows past the point where speedup is needed then you need to start precalculating stuff (for real time updates using triggers that update score in movies table or some other intermediate table dedicated for that, other methods)
Just add the second order you want separated by comma .try this
SELECT data_id, COUNT(point), SUM(point)
FROM voting_table
WHERE data_type='1'
GROUP BY data_id
order by SUM(point)/COUNT(point) ,COUNT(point)
DESC limit 100
Try changing your order by clause to be:
order by SUM(point)/COUNT(point) desc, COUNT(point) desc
As it stands, your query appears to be efficient.