Reputation: 460
Assume we have the following MYSQL-Query to generate a leaderboard:
SELECT x.player_id, x.position,x.leaderboard_value
FROM (SELECT player_id,@rownum := @rownum + 1 AS position,leaderboard_value
FROM table1
JOIN (SELECT @rownum := 0) r
WHERE restrictive_value<200
ORDER BY leaderboard_value DESC) x
which produces a leaderboard like this:
Textfile as CSV: https://www.dropbox.com/s/70xw3ocbonqs98s/sql.csv?dl=0
How do I change or extend the query to deliver a specific players position, and the total amount of positions (highest position)
for above table and player_id=10649 I'd expect a result-table with 1 row containing these fields:
position: 6, totalpositions: 20, percentage= 0.3 (which is 6/20)
Backstory of this is to join this percentage with a different table rank_map(rank_id,minvalue,maxvalue) defining ranks (rank is "9" when this value is between 0.2 and 0.4 for example)
In the end this query should simply return rank: 9 as answer
Thank you very much.
UPDATE:
with Gordon Linoffs answer, using this query:
SELECT MAX(CASE WHEN player_id = 10649 THEN position END) as play_position,
COUNT(*) as total_position,
MAX(CASE WHEN player_id = 10649 THEN position END) / COUNT(*) as ratio
FROM (SELECT t1.*, @rownum := @rownum + 1 AS position
FROM table1 t1 CROSS JOIN
(SELECT @rownum := 0) r
WHERE restrictive_value < 200
ORDER BY leaderboard_value DESC
) x;
A final step is left, which is, how to join it with the rank(rank_id, minvalue,maxvalue) table to only get the rank_id row where ratio is between minvalue and maxvalue?
Upvotes: 3
Views: 1529
Reputation: 147256
You can achieve this by adding COUNT(*)
to your subquery JOIN
to get the total number of rows, then display the percentage as position/total:
SELECT x.player_id, x.position,x.leaderboard_value, (x.position/x.total) AS percentage
FROM (SELECT total, player_id,@rownum := @rownum + 1 AS position,leaderboard_value
FROM table1
JOIN (SELECT @rownum := 0) r
JOIN (SELECT COUNT(*) AS total FROM table1) c
WHERE restrictive_value<200
ORDER BY leaderboard_value DESC) x
Some of the output from your sample data:
player_id position leaderboard_value percentage
2730 1 1090 0.01
1369848 2 1017 0.02
1665922 3 960 0.03
1607632 4 910 0.04
1853500 5 909 0.05
10649 6 883 0.06
1538490 7 877 0.07
1898051 8 866 0.08
1510162 9 828 0.09
1898129 10 825 0.1
1863538 11 821 0.11
1522562 12 806 0.12
1380267 13 805 0.13
1404318 14 797 0.14
8793 15 769 0.15
21793 16 767 0.16
14658 17 756 0.17
1690659 18 729 0.18
1429094 19 723 0.19
1727977 20 719 0.2
To get the data for only a specific player, just add a WHERE x.player_id=nnnn
clause e.g.
SELECT x.player_id, x.position,x.leaderboard_value, (x.position/x.total) AS percentage
FROM (SELECT total, player_id,@rownum := @rownum + 1 AS position,leaderboard_value
FROM table1
JOIN (SELECT @rownum := 0) r
JOIN (SELECT COUNT(*) AS total FROM table1) c
WHERE restrictive_value<200
ORDER BY leaderboard_value DESC) x
WHERE x.player_id = 10649
Output:
player_id position leaderboard_value percentage
10649 6 883 0.06
To then get their ranking from the rank table, you just need to JOIN
it based on percentage (note you have to use the formula as you can't use an alias in a JOIN
):
SELECT x.player_id, x.position,x.leaderboard_value, (x.position/x.total) AS percentage, m.rank_id
FROM (SELECT total, player_id,@rownum := @rownum + 1 AS position,leaderboard_value
FROM table1
JOIN (SELECT @rownum := 0) r
JOIN (SELECT COUNT(*) AS total FROM table1) c
WHERE restrictive_value<200
ORDER BY leaderboard_value DESC) x
JOIN rank_map m ON m.minvalue <= (x.position/x.total) AND m.maxvalue > (x.position/x.total)
WHERE x.player_id = 10649
Output:
player_id position leaderboard_value percentage rank_id
10649 6 883 0.06 3
Upvotes: 4
Reputation: 1271061
For this purpose, you can use conditional aggregation:
SELECT MAX(CASE WHEN player_id = 10649 THEN position END) as play_position,
COUNT(*) as total_position,
MAX(CASE WHEN player_id = 10649 THEN position END) / COUNT(*) as ratio
FROM (SELECT t1.*, @rownum := @rownum + 1 AS position
FROM table1 t1 CROSS JOIN
(SELECT @rownum := 0) r
WHERE restrictive_value < 200
ORDER BY leaderboard_value DESC
) x;
You can use either COUNT(*)
or MAX(position)
for the highest position.
Upvotes: 2