SQL 用户评分分组排名

SQL User Score ranking by grouping

我有以下排名系统。

SET @1=0;

SELECT id, username, magic_xp, @i:=@i+1 AS rank
  FROM hs_users
 ORDER 
    BY magic_xp DESC;

hs_users
id  username     magic_xp rank
988 5hapescape   14926854    1
737 Ozan         13034431    2
989 Kurt         13034431    3
  6 LEGACY              0    4
 11 Bobby               0    5
276 Bobby123            0    6
345 Mynamesjason        0    7
450 Demon Spawn         0    8
987 Satan               0    9

如您所见,我有 2 个用户拥有相同的 xp。

我想让它们都具有 rank = 2,其余的应该遵循 3

我怎样才能像这样对它们进行分组?

|  username  | magic_xp | rank |
| ---------- + -------- + ---- |
| ShapeScape |     1000 |    1 |
| Kurt       |      100 |    2 |
| Ozan       |      100 |    2 |
| Legacy     |       10 |    3 |

查询

set @i := 0;
set @lagxp := null;

select id, username, magic_xp, 
@i := if(@lagxp = magic_xp, @i,
          if(@lagxp := magic_xp, @i + 1, @i + 1)) as rank
from hs_users
order by magic_xp desc
;

SELECT id, username, magic_xp, 
IF (@score=hs_users.magic_xp, @rank:=@rank, @rank:=@rank+1) as rank,
@score:=hs_users.magic_xp score
FROM hs_users, (SELECT @score:=0, @rank:=0) r
ORDER BY magic_xp DESC;

输出

+-----+------------+----------+------+----------+
| id  |  username  | magic_xp | rank |  lagxp   |
+-----+------------+----------+------+----------+
| 988 | Shapescape | 14926894 |    1 | 14926894 |
| 737 | Ozan       | 13034431 |    2 | 13034431 |
| 989 | Kurt       | 13034431 |    2 | 13034431 |
|   6 | Legacy     |        0 |    3 |        0 |
+-----+------------+----------+------+----------+

sqlfiddle

在MySQL中,最高效的方法是使用变量:

  select t.*,
         (@rank := if(@magic_xp = magic_xp, @rank,
                      if(@magic_xp := magic_xp, @rank + 1, @rank + 1)
                     )
         ) as rank
  from table t cross join
       (select @rank := 0, @magic_xp := NULL) params
  order by magic_xp desc;

注意变量的复杂表达式。两个变量的赋值都在一个表达式中。这是故意的。 MySQL 不保证 SELECT 中表达式的赋值顺序,有时甚至不按顺序求值。单个表达式是执行此逻辑的安全方法。

SQL 中更标准的方法是使用相关子查询:

select t.*,
       (select count(distinct t2.magic_xp)
        from table t2
        where t2.magic_xp >= t.magic_xp
       ) as rank
from table t;

提出解决方案:)

SELECT id, username, magic_xp, 
IF (@score=hs_users.magic_xp, @rank:=@rank, @rank:=@rank+1) as rank,
@score:=hs_users.magic_xp score
FROM hs_users, (SELECT @score:=0, @rank:=0) r
ORDER BY magic_xp DESC;

感谢@amdixon

select 
  @rank:=if(magic_xp=@prev_magic_xp,@rank,@rank+1) as rank,
  username,
  magic_xp,
  @prev_magic_xp:=magic_xp as prev_magic_xp

from user,(select @rank:=0,@prev_magic_xp="") t

order by magic_xp desc

供您参考:http://sqlfiddle.com/#!9/09bb3/2