Make a leaderboard ranking from table in sql - mysql

I have a database with names and their scores and I'd like to insert into the table the rank according to the score. My database looks a bit like this:
phpmyadmin database
I would like to make it so when the score is higher than a rank the ranks change in the database. So if there were a player 1 with 500 points and a player 2 with 1500 points, the code would insert the rank into the rank column corresponding with the player's name.
Like this:
Rank
Name
Score
1
Player2
1500
2
Player1
500

Don't store the RANK in the database calculate it on the fly when you read the data using the RANK() function.
SELECT
Player,
Score,
RANK() OVER(ORDER BY Score DESC) AS 'RANK'
FROM
PlayerScore
ORDER BY
Score DESC
If you can have tied scores you can use DENSE_RANK(). This would give you ranks of 1,2,2,3. RANK would just give you 1,2,2,4

Related

Calculating rank not working - Mysql

I have a DB Table user_points which contains user's points and I am trying to calculate ranking based on points. It is working fine for all users except users having 1 point.
If user have 1 point it is showing it's rank as 0 but it should display it's rank as last or in last numbers like: 12083 etc.
Higher points are, ranking should be higher as well. For example:
1000 points = rank 1
1 point = rank 1223
Following is the query.
SELECT id, mobileNo, points,
FIND_IN_SET( points, (SELECT GROUP_CONCAT( points ORDER BY points DESC )
FROM users_points )) AS rank
FROM users_points
WHERE mobileNo = '03214701777'
What should I change to fix it?
SELECT a.id, a.mobileNo, a.points,
IFNULL((SELECT COUNT(*) AS rank
FROM users_points b
WHERE b.points<a.points), 0)+1 as rank
FROM user_points a
WHERE a.mobileNo = '03214701777'
Seems to be what you are looking for. While it is still very innefficient it is better than your approach using FIND_IN_SET(). If you really want to use FIND_IN_SET() then you need to pad the scores to a consistent width and divide by the width+1 to get the rank.

Select rank of a specific player sql query

I'm trying to make a query and I already searched for an answer on stackof but didn't find one matching my needs.
I have a table named player in which there are two columns, "nickname" and "score".
I use this query to get the top 5 players:
SELECT nickname, score
FROM player
ORDER BY score DESC LIMIT 5;
and I got this as the answer:
nickname - score:
zod - 30
ciao - 20
jiji - 20
mayina - 20
jon - 0.
Now, I'd like to have the rank of a single player, let's say "jiji" and get 3 as a result, because it's the third result in the list.
I tried many queries like
SELECT COUNT(*) AS rank
FROM player
WHERE score >= (SELECT score FROM player WHERE nickname = 'jiji')
but they always return 4 for "jiji" or "ciao", which is the rank of the last player who gets 20 as score in that table.
How can I get to have 3 for "jiji", instead? Thank you very much.
Try this:
SET #rank=0;
SELECT *
FROM (SELECT #rank:=#rank+1, nickname, score
FROM player
ORDER BY score
DESC) AS t
WHERE t.nickname = 'jiji';
Correct comment about this not being stable in case of score ties. To make it stable, we can change the sorting to be based on score and then nickname:
SELECT *
FROM (SELECT #rank:=#rank+1, nickname, score
FROM player
ORDER BY score, nickname
DESC) AS t
WHERE t.nickname = 'jiji';
Using commonly used definitions, the rank for jiji would be:
SELECT count(*) + 1 AS rank
FROM player
WHERE score > (SELECT score FROM player WHERE nickname = 'jiji');
This returns "2", because there are ties when score = 30.
If you want the rank to be stable and different for each row, you need an additional key. An obvious key (in this case) is nickname:
SELECT count(*) AS rank
FROM player p CROSS JOIN
(SELECT score FROM player WHERE nickname = 'jiji') s
WHERE p.score > s.score or
(p.score = s.score and p.nickname <= 'jiji');

MySQL ranking feature

I am trying to create a ranking system using the data in my table. It has 2 columns, name and score. One user can have multiple scores. This is what I have so far:
("SELECT name, score, FIND_IN_SET( score, (SELECT GROUP_CONCAT ( score ORDER BY score DESC ) FROM data )) AS rank FROM scores");
But this command lists all the user's previous scores when I only need the highest score.
Does anyone know how I can achieve this?
Try
SELECT name, sum(score) from scores group by name order by sum(score) desc limit 1
And if you don't want to sum then use
SELECT name, max(score) from scores
The below query will pop the list of name in the order of highest score respectively.
select name, max(score) as score from scores group by name order by score desc
You can use SELECT DISTINCT name, score ...
and Select TOP 1 and ORDER BY

MySQL Scoring system - Getting a single users rank from a score cloud

I have a table of scores for games and users, users can have many scores for each game:
USER GAME SCORE TIMESTAMP
1 1 125 123456
2 1 120 123457
1 2 10293 123458
2 2 10253 123459
1 1 130 123460
Obviously there are a lot more users and games, but you get the idea, I'm logging every score they get and storing it with a timestamp to get scores in specific timeframes.
What I need to do is to get a users individual rank in a game, for instance:
user 1 - game 1 - rank 1
user 2 - game 1 - rank 2
but doing a query
SELECT COUNT(DISTINCT user)
FROM scores
WHERE game = 1
AND score > $user_2_score
AND timestamp < $time_limit
ORDER BY score DESC
will put the user in 3rd place because user 1 has two scores higher than it. I thought COUNT(DISTINCT user) would solve the problem but for some reason it didn't!
(obviously I am getting the users highest score from another query and passing it to this query)
Is there any way of doing this in MySQL, or a better query I could use to get better results?
Maybe using GROUP BY would be better :
SELECT user,game, SUM(score) AS scorer
FROM scores
GROUP BY user, game
ORDER BY scorer DESC
If you want to get results for exact game, then you can use this query -
SELECT
user,
SUM(score) sum_score,
#r:=#r + 1 rank
FROM
scores, (SELECT #r:=0) t
WHERE
game = 1
GROUP BY
user
ORDER BY
sum_score DESC;

sql and getting elements around a specific one

My sql database stores the highscores for the players of a game like this:
playerName
scores
To show the scores I'm trying to create a query that returns for a playerId "joe" the positon of joe as well as one player with more and less points than joe:
(rank) (playerName) (scores)
5000 luci 2001
5001 joe 1900
5002 marc 1750
(I added the rank here just to make it more clear. It isn't stored and represents just the position in the list when sorting by the scores)
Is there a way to do soemthing like this with a query without getting half of the database as result?
You'd ideally want to be using window functions to do this, namely row_number(), lead() and lag().
These are not available in MySQL, but here are a few workarounds (also row_number(), picked up from the same author).
Using window functions:
with
players as (
select row_number() over w as rank,
playername,
scores
from players
window w (order by scores desc)
),
player as (
select rank
from players
where playername = 'joe'
)
select rank,
playername,
scores
from players
join player on players.rank between player.rank - 1 and player.rank + 1
Alternatively (slightly faster):
with
player_range as (
select scores - 100 as scores -- or whatever is large enough based on your stats
from players
where playername = 'joe'
),
players as (
select row_number() over w as rank,
players.playername,
players.scores
from players
join player_range
on player_range.scores <= players.scores
window w (order by scores desc)
),
player as (
select rank
from players
where playername = 'joe'
)
select rank,
playername,
scores
from players
join player on players.rank between player.rank - 1 and player.rank + 1
To determine joe's rank you have to query the db and order by scores.