如何使用LIMIT获得MySQL的分数排名?

时间:2016-01-19 22:42:39

标签: mysql

这就是我目前所拥有的:

SELECT id, score, username,
CASE
WHEN @prevRank = score THEN @curRank
WHEN @prevRank := score THEN @curRank := @curRank + 1
END AS rank
FROM users u,
SELECT @curRank :=0, @prevRank := NULL) r
ORDER BY score DESC LIMIT 5, 5;

我希望从第5行开始接下来的5个排名,但排名会从1开始重新排名。如何才能让排名从相对于所有行的正确排名开始?

示例数据:http://pastebin.com/i3PsRWdg

Everyone

+----+--------+-----------+------+
| id | scores | username  | rank |
+----+--------+-----------+------+
| 24 |     23 | fl        |    1 |
|  3 |      9 | test      |    2 |
|  6 |      9 | usernine  |    2 |
|  5 |      7 | test3     |    3 |
| 11 |      7 | test9     |    3 |
| 26 |      5 | tryagain  |    4 |
| 12 |      5 | newUser   |    4 |
|  7 |      3 | test6     |    5 |
| 14 |      1 | new3      |    6 |
|  4 |      1 | test2     |    6 |
| 13 |      0 | new2      | NULL |
| 25 |      0 | newu      |    6 |
| 23 |      0 | new       |    6 |
| 22 |      0 | usernine  |    6 |
| 21 |      0 | usernine  |    6 |
| 20 |      0 | test      |    6 |
| 19 |      0 | usernine  |    6 |
| 18 |      0 | usernine  |    6 |
| 17 |      0 | usernine  |    6 |
| 15 |      0 | usernine  |    6 |
| 16 |      0 | test9     |    6 |
+----+--------+-----------+------+

LIMIT 1,5 -> correct

+----+--------+-----------+------+
| id | scores | username  | rank |
+----+--------+-----------+------+
|  3 |      9 | test      |    1 |
|  6 |      9 | usernine  |    1 |
|  5 |      7 | test3     |    2 |
| 11 |      7 | test9     |    2 |
| 26 |      5 | tryagain  |    3 |
+----+--------+-----------+------+

LIMIT 5,5 -> incorrect

+----+--------+----------+------+
| id | scores | username | rank |
+----+--------+----------+------+
| 12 |      5 | newUser  |    1 |
| 26 |      5 | usernine |    1 |
|  7 |      3 | test6    |    2 |
|  4 |      1 | test2    |    3 |
| 14 |      1 | new3     |    3 |
+----+--------+----------+------+

Should be this:

+----+--------+----------+------+
| id | scores | username | rank |
+----+--------+----------+------+
| 12 |      5 | newUser  |    4 |
| 26 |      5 | usernine |    4 |
|  7 |      3 | test6    |    5 |
|  4 |      1 | test2    |    6 |
| 14 |      1 | new3     |    6 |
+----+--------+----------+------+

2 个答案:

答案 0 :(得分:1)

您正试图在错误的级别解决问题。它在数据集中考虑您的数据库不在行中思考。它的世界由整齐的矩形表组成,而不是行或字段。您在@curRank hack中使用的“每行添加”的整个概念实际上在SQL Server中不起作用,例如因为它正确地将整个集合视为原子实体。

这让我们回到你的问题是架构,而不是数据库相关。数据库负责存储,组织,聚合和返回数据。对行进行编号肯定不是,它属于您的业务逻辑或您的表示逻辑。

要在业务逻辑中解决此问题,您可以将5偏移量提供给此查询,您可以将结果行存储在带编号的数组中。例如,在网站的表示层中,您将使用像<ol start="6">这样的有序列表。

答案 1 :(得分:0)

您可以创建一个aditional变量来跟踪row_number

另外,我使用IF()代替案例,因为当score = 0产生排名null并且没有创建rank 7时,您的版本会出现错误

<强> SQL Fiddle Demo

SELECT *
FROM (
    SELECT id, score, username,
        @curRank := IF(@prevRank = score,
                       @curRank ,
                       IF(@prevRank := score,  @curRank + 1,  @curRank + 1 )
                      ) as rank,
        (@row := @row + 1) as rn
    FROM users u
    CROSS JOIN (SELECT @curRank := 0, @prevRank := NULL, @row := 0) r
    ORDER BY score DESC
    ) T
WHERE rn >  5  
  AND rn <= 10

<强>输出

| id | score | username | rank | rn |
|----|-------|----------|------|----|
| 26 |     5 | tryagain |    4 |  6 |
| 12 |     5 |  newUser |    4 |  7 |
|  7 |     3 |    test6 |    5 |  8 |
| 14 |     1 |     new3 |    6 |  9 |
|  4 |     1 |    test2 |    6 | 10 |