SELECT用户在MySQL上的排名偏移

问题描述

我正在尝试在MysqL中进行查询,该查询仅从表中返回10个用户,但其排名值是xp列的ORDER结果。现在我有这个:

SELECT id,xp,@curRank := @curRank + 1 AS rank
    FROM usuarios,(SELECT @curRank := 0) r
    ORDER BY xp DESC LIMIT 10;

获取前10个用户时,它看起来运行良好。

+--------------------+------+------+
| id                 | xp   | rank |
+--------------------+------+------+
| 373901344995803138 | 5863 |    1 |
| 701198768049225770 | 5692 |    2 |
| 239203656405221376 | 4961 |    3 |
| 692489002942726154 | 4508 |    4 |
| 416988898628206593 | 3669 |    5 |
| 312003290378534912 | 3155 |    6 |
| 608344569381126167 | 3059 |    7 |
| 671949142473310238 | 3041 |    8 |
| 549743978191519744 | 2991 |    9 |
| 592440479577145383 | 2519 |   10 |
+--------------------+------+------+

但是,当我尝试获取LIMIT 10,10来吸引11至20岁的用户时,尽管他们是有序的,但他们的总体排名是不正确的,因为@curRank并没有在所有用户之前增加偏移量。

+--------------------+------+------+
| id                 | xp   | rank |
+--------------------+------+------+
| 638196238436532234 | 1888 |    1 |
| 601269358349516833 | 1447 |    2 |
| 548357514497097743 | 1338 |    3 |
| 203591312031744000 | 1330 |    4 |
| 379034072519016469 | 1283 |    5 |
| 563804445654122497 | 1086 |    6 |
| 421296425981181952 | 1025 |    7 |
| 263816867100098560 |  850 |    8 |
| 631330775379214371 |  776 |    9 |
| 442529076511637504 |  702 |   10 |
+--------------------+------+------+

使用LIMIT时,我不知道使全球排名有效的方法

解决方法

在MySQL 8.0中,仅使用窗口功能,如Gordon Linoff所演示的。

在早期版本中,基本上,您需要一个子查询来执行所需的操作。我建议:

SELECT *
FROM (
    SELECT id,xp,@curRank := @curRank + 1 AS rank
    FROM (SELECT * FROM usuarios ORDER BY xp DESC) u
    CROSS JOIN (SELECT @curRank := 0) r
    ORDER BY xp DESC
) t
ORDER BY xp DESC 
LIMIT 10,10;

子查询将所有用户排在第一位,然后您可以安全地过滤外部查询。请注意,该查询首先在子查询中按xp对表进行预排序:这样比较安全(在MySQL中,用户变量比较棘手)。

实际上,您甚至不需要外部查询LIMIT;您可以改用WHERE子句:

SELECT *
FROM (
    SELECT id,@curRank := @curRank + 1 AS rank
    FROM (SELECT * FROM usuarios ORDER BY xp DESC) u
    CROSS JOIN (SELECT @curRank := 0) r
    ORDER BY xp DESC
) t
WHERE rank BETWEEN 11 AND 20
ORDER BY rank
,

相反,请使用row_number()

SELECT id,row_number() over (order by cp desc) as rank
FROM usuarios
ORDER BY xp DESC
LIMIT 10;