【问题标题】:SELECT user ranking on MySQL by an offset通过偏移量在 MySQL 上选择用户排名
【发布时间】:2021-01-30 04:22:50
【问题描述】:

我正在尝试在 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 sql sql-order-by window-functions sql-limit


    【解决方案1】:

    在 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, 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
    WHERE rank BETWEEN 11 AND 20
    ORDER BY rank
    

    【讨论】:

    • 嗯,我刚刚尝试了上面的两个示例,但它在两个查询中都提高了ERROR 1248 (42000): Every derived table must have its own alias
    • @Eleiber:我的错。固定
    【解决方案2】:

    改为使用row_number():

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

    【讨论】:

    • 试过了,但它给我带来了语法错误,也许row_number() 在我的 MySQL 版本中不是一个实际的函数。
    • 我刚刚在 Ubuntu 的 MySQL 8 上测试了这个答案,它不起作用,因为看起来你不能使用“rank”作为变量名。
    • @Eleiber 。 . .更改名称。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多