Search code examples
mysqlsqlgroup-byranking

SQL Rank Function with Group


I want to rank the total stats of a group of users and assign a rank variable to them. I used this thread for the Rank variable.

This is my Query atm:

SELECT @rank := @rank + 1 AS rank
     , SUM(stats.points) AS x 
  FROM 
     ( SELECT @rank := 0 ) r
     , groups 
  LEFT 
  JOIN user_group 
    ON groups.id = user_groups.clan 
  LEFT 
  JOIN stats 
    ON user_groups.user = stats.id 
 GROUP  
    BY groups.id 
 ORDER 
    BY x DESC

RANK | points 
--------------
  47 |    3400     
  1  |    2500     
  75 |    1200     

As you can see the Sorting by Points works fine, but the Rank variable seems to just pick random values. Can anyone find a way to assign the rank correctly?


Solution

  • Use a subquery for the aggregation and ordering:

    SELECT id, sum_points, @rank := @rank + 1 AS rank
    FROM (SELECT g.id, SUM(s.points) AS sum_points
          FROM groups g LEFT JOIN
               user_group ug
               ON g.id = ug.clan LEFT JOIN
               stats s
               ON ug.user = s.id
          GROUP BY g.id
          ORDER BY sum_points DESC
         ) s CROSS JOIN
         (SELECT @rank := 0) params;
    

    This has been an issue in MySQL for a while -- variables don't work well with aggregation and ordering.

    Note that in MySQL 8+, this is much more simply written as:

    SELECT g.id, SUM(s.points) AS sum_points,
           ROW_NUMBER() OVER (ORDER BY SUM(s.points) DESC) as rank
    FROM groups g LEFT JOIN
         user_group ug
         ON g.id = ug.clan LEFT JOIN
         stats s
         ON ug.user = s.id
    GROUP BY g.id