1

I'm trying to get a users ranking getting his highest performances in every beatmap.

I get the user highest performance in every beatmap (only taking the top 5 performances) and adding them together, but it fails when the highest performance in one beatmap is repeated... because it counts twice

I'm based in this solution, but it doesn't works well for me...

Using MySQL 5.7

What i'm doing wrong?

Fiddle

Using this code:

SET group_concat_max_len := 1000000;

SELECT @i:=@i+1 rank, x.userID, x.totalperformance FROM (SELECT r.userID, SUM(r.performance) as totalperformance 
FROM 
(SELECT Rankings.*
FROM   Rankings INNER JOIN (
  SELECT   userID, GROUP_CONCAT(performance ORDER BY performance DESC) grouped_performance
  FROM     Rankings
  GROUP BY userID) group_max
  ON Rankings.userID = group_max.userID
     AND FIND_IN_SET(performance, grouped_performance) <= 5

ORDER BY
  Rankings.userID, Rankings.performance DESC) as r
  GROUP BY userID) x
  JOIN 
     (SELECT @i:=0) vars
 ORDER BY x.totalperformance DESC

Expected result:

+------+--------+------------------+
| rank | userID | totalperformance |
+------+--------+------------------+
| 1    | 1      | 450              |
+------+--------+------------------+
| 2    | 2      | 250              |
+------+--------+------------------+
| 3    | 5      | 140              |
+------+--------+------------------+
| 4    | 3      | 50               |
+------+--------+------------------+
| 5    | 75     | 10               | 
+------+--------+------------------+
| 6    | 45     | 0                | --
+------+--------+------------------+
| 7    | 70     | 0                | ----> This order is not relevant
+------+--------+------------------+
| 8    | 76     | 0                | --
+------+--------+------------------+

Actual Result:

+------+--------+------------------+
| rank | userID | totalperformance |
+------+--------+------------------+
| 1    | 1      | 520              |
+------+--------+------------------+
| 2    | 2      | 350              |
+------+--------+------------------+
| 3    | 5      | 220              |
+------+--------+------------------+
| 4    | 3      | 100              |
+------+--------+------------------+
| 5    | 75     | 10               |
+------+--------+------------------+
| 6    | 45     | 0                | --
+------+--------+------------------+
| 7    | 70     | 0                | ----> This order is not relevant
+------+--------+------------------+
| 8    | 76     | 0                | --
+------+--------+------------------+
  • What version of mysql are you on? – P.Salmon Sep 11 '20 at 11:17
  • Duplicates. If `grouped_performance` is `'10,9,8,7,6,6,5,...'` then FIND_IN_SET() will give 5 for both `6`, not 5 and 6. See https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=19ee91dc0ec0fd1f9928008af5c7135d - most inner subquery and its outer with additional column. The solution which you refer on needs the concatenated values to be unique. – Akina Sep 11 '20 at 11:17
  • 1
    Can you recheck with your expected output and data in fiddle. It is inconsistent, if you are picking only top 5 values for each user then the sum should be 250 for user id 2 instead of 350.. – Akhilesh Mishra Sep 11 '20 at 12:12
  • Thanks, im sorry, the fiddle are inconsistent, i eddited it with the correct one, let me check your answer – Arturo Rodriguez Sep 11 '20 at 21:28

1 Answers1

1

As you have mentioned that you are picking only top 5 performances per user across beatmaps then you can try this way:

select @i:=@i+1, userid,performance from (
select userid,sum(performance) as performance from (
select 
  @row_number := CASE WHEN @last_category <> t1.userID THEN 1 ELSE @row_number + 1 END AS row_number,
  @last_category :=t1.userid,
t1.userid,
t1.beatmapid,
t1.performance

from (
select 
 userid, beatmapid,
 max(performance) as performance
from Rankings 
group by userid, beatmapid
) t1 
CROSS JOIN (SELECT @row_number := 0, @last_category := null) t2
ORDER BY t1.userID , t1.performance desc
) t3
where row_number<=5
group by userid
)
t4 join  (SELECT @i := 0 ) t5
order by performance desc

Above query will not consider duplicate Performance Score and pick only top 5 performance values.

DEMO

Akhilesh Mishra
  • 5,876
  • 3
  • 16
  • 32
  • Hi, i tested in my server and it fails in some exceptions... like only two duplicated performances in 1st place and no more performances, i updated the post and the fiddle with these exceptions – Arturo Rodriguez Sep 11 '20 at 22:43
  • @ArturoRodriguez Edited the answer. In your expected output for user ID 3 should be 100 not 50 – Akhilesh Mishra Sep 12 '20 at 04:26
  • No, it's correct 50, the are two records with 50 in the same beatmap, we are taking only the highest one time – Arturo Rodriguez Sep 12 '20 at 04:41
  • The answer is almost perfect, but the userID 3 has two records with 50 performance in the same beatmap so, it's a duplicate, and we only have to take one time – Arturo Rodriguez Sep 12 '20 at 05:23
  • @ArturoRodriguez once again i have updated the answer. Hope this time you will get what you want. – Akhilesh Mishra Sep 12 '20 at 08:32