I am developing a game like app with an leaderboard and want the leaderboard to have this features:
- Show Top 100
- Show Top 100 Monthly, Weekly, Daily
- Show Trends next to every User (if the user moved up on the leaderboard show green up arrow, and if down then red down arrow)
Currently I have two tables:
user:
besides all userspecific data the table also has a points column
Query to get alltime TOP 100:
SELECT uuid, points FROM user ORDER BY points DESC LIMIT 100
user_scores:
COLUMNS: id, uuid, user_uuid, game_uuid, score_change, timestamp
Here a few Pseudo Example Rows:
|id| uuid | user_uuid | game_uuid | score_change|ts|
|--|-----------|----------------|----------------|-------------|--|
|1 | some_uuid | uuid_of_user_a | uuid_of_game_a | 2 |22|
|2 | some_uuid | uuid_of_user_a | uuid_of_game_b | 1 |24|
|3 | some_uuid | uuid_of_user_a | uuid_of_game_c | 3 |28|
after every game the score change of a user gets written into here.
Query to get e.g. the weekly leaderboard:
SELECT SUM(score_change) AS total, user_uuid
FROM user_scores WHERE timestamp > week_begin & timestamp < week_end
GROUP BY user_uuid ORDER BY total DESC LIMIT 100
Of course i could also query the alltime TOP 100 out of the user_scores table, but i thought this is probably more efficient, because i don’t have to fetch through the whole user_scores table.
So far so good. But how do implement the trends of the ranks?
3
Answers
You should add timestamp column to each score change.
Calculate the score on fly.
Using CTE’s and Window functions should be able to give you the output you’re looking for.
Try the following code below:
Current rankings and Previous rankings
Combine to determine trends
NOTE
Adjust
this_week_start
,this_week_end
,last_week_start
, andlast_week_end
to your timestamp calculation logicYou can left-join the previous week’s result, each set row-numbered by the
total
, and then subtract the row-numbers from each other to get the trend.You need to think about what tyep of ranking you want:
ROW_NUMBER
RANK
orDENSE_RANK
.You are right that filtering by
timestamp
will improve performance, but you would need proper indexing, something like(timestamp, user_uuid) INCLUDE (score_change)
.