MySQL查询更新排名

时间:2017-05-29 20:40:53

标签: mysql rank

我有一个mysql表,其中userid,rating和ranking为字段。该表很大(> 10K行)。我试图根据评级更新单个查询中每行的排名列(更高的评级是更低的排名)。如果2个或更多用户具有相同的评级,则他们具有相同的排名,但是下一个排名将跳过那么多用户(如果2个用户具有排名5,则下一个用户将排名为7)。

我试图通过以下查询来实现这一目标,但不知道我哪里出错了。

UPDATE userprofile
            JOIN (SELECT p.userid,
                         IF(@last_rating<> p.rating,
                            @cur_rank := @cur_rank + @next_rank,
                            @cur_rank)  AS ranking,
                         IF(@last_rating= p.rating,
                            @next_rank := @next_rank + 1,
                            @next_rank := 1),
                         @last_rating:= p.rating
                    FROM userprofile p
                    JOIN (SELECT @cur_rank := 0, @last_rating:= -1, @next_rank := 1) r
                   ORDER BY  p.rating DESC
                  ) ranks ON (ranks.userid = userprofile.userid)
        SET userprofile.ranking = ranks.ranking

这是查询之前的表格示例

+--------+--------+-----+------+------------+--------+--------------+---------+---------------+
| userid | played | won | lost |   streak   | rating | ratingchange | ranking | currentgameid |
+--------+--------+-----+------+------------+--------+--------------+---------+---------------+
|      1 |      1 |   0 |    0 | A          |      0 |            0 |       0 |             6 |
|      2 |      1 |   1 |    0 | W          |     50 |           50 |       0 |             2 |
|      7 |     13 |   4 |    5 | AWLLLWWLLW |    108 |           48 |       0 |             0 |
|      8 |      6 |   6 |    0 | WWWWWW     |    198 |           48 |       0 |             0 |
|      9 |      1 |   0 |    0 | A          |      0 |            0 |       0 |             0 |
|     10 |      1 |   1 |    0 | W          |     50 |           50 |       0 |             0 |
|     11 |      7 |   5 |    2 | WWWLWWL    |    142 |          -48 |       0 |             0 |
|     12 |      7 |   1 |    6 | LLLWLLL    |      0 |            0 |       0 |            26 |
|     13 |      5 |   3 |    1 | LWWAW      |     71 |           71 |       0 |             0 |
|     14 |      1 |   1 |    0 | W          |     71 |           71 |       0 |             0 |
|     15 |      0 |   0 |    0 |            |      0 |            0 |       0 |            26 |
+--------+--------+-----+------+------------+--------+--------------+---------+---------------+

在查询之后

+--------+--------+-----+------+------------+--------+--------------+---------+---------------+
| userid | played | won | lost |   streak   | rating | ratingchange | ranking | currentgameid |
+--------+--------+-----+------+------------+--------+--------------+---------+---------------+
|      1 |      1 |   0 |    0 | A          |      0 |            0 |       1 |             6 |
|      2 |      1 |   1 |    0 | W          |     50 |           50 |       2 |             2 |
|      7 |     13 |   4 |    5 | AWLLLWWLLW |    108 |           48 |       3 |             0 |
|      8 |      6 |   6 |    0 | WWWWWW     |    198 |           48 |       4 |             0 |
|      9 |      1 |   0 |    0 | A          |      0 |            0 |       5 |             0 |
|     10 |      1 |   1 |    0 | W          |     50 |           50 |       6 |             0 |
|     11 |      7 |   5 |    2 | WWWLWWL    |    142 |          -48 |       7 |             0 |
|     12 |      7 |   1 |    6 | LLLWLLL    |      0 |            0 |       8 |            26 |
|     13 |      5 |   3 |    1 | LWWAW      |     71 |           71 |       9 |             0 |
|     14 |      1 |   1 |    0 | W          |     71 |           71 |       9 |             0 |
|     15 |      0 |   0 |    0 |            |      0 |            0 |      11 |            26 |
+--------+--------+-----+------+------------+--------+--------------+---------+---------------+

如果我使用如下的select语句,它会在ranking.ranking列中给出我预期的结果,但SET语句没有按预期工作。

SELECT userprofile.userid, userprofile.rating, ranks.userid, ranks.ranking FROM userprofile
            JOIN (SELECT p.userid,
                         IF(@last_rating<> p.rating,
                            @cur_rank := @cur_rank + @next_rank,
                            @cur_rank)  AS ranking,
                         IF(@last_rating= p.rating,
                            @next_rank := @next_rank + 1,
                            @next_rank := 1),
                         @last_rating:= p.rating
                    FROM userprofile p
                    JOIN (SELECT @cur_rank := 0, @last_rating:= -1, @next_rank := 1) r
                   ORDER BY  p.rating DESC
                  ) ranks ON (ranks.userid = userprofile.userid)

选择查询的结果

+--------+--------+--------+---------+
| userid | rating | userid | ranking |
+--------+--------+--------+---------+
|      8 |    198 |      8 |       1 |
|     11 |    142 |     11 |       2 |
|      7 |    108 |      7 |       3 |
|     13 |     71 |     13 |       4 |
|     14 |     71 |     14 |       4 |
|      2 |     50 |      2 |       6 |
|     10 |     50 |     10 |       6 |
|      1 |      0 |      1 |       8 |
|      9 |      0 |      9 |       8 |
|     12 |      0 |     12 |       8 |
|     15 |      0 |     15 |       8 |
+--------+--------+--------+---------+

2 个答案:

答案 0 :(得分:1)

您可以创建时态表,然后执行更新吗?

<强> SQL DEMO

CREATE TABLE test as 
SELECT userprofile.*, ranks.ranking  as newRank
FROM userprofile
JOIN (SELECT p.userid,
             IF(@last_rating<> p.rating,
                @cur_rank := @cur_rank + @next_rank,
                @cur_rank)  AS ranking,
             IF(@last_rating= p.rating,
                @next_rank := @next_rank + 1,
                @next_rank := 1),
             @last_rating:= p.rating
      FROM userprofile p
      JOIN (SELECT @cur_rank := 0, @last_rating:= -1, @next_rank := 1) r
      ORDER BY  p.rating DESC
    ) ranks 
ON (ranks.userid = userprofile.userid);

更新

UPDATE userprofile
JOIN test
  ON userprofile.`userid`  = test.`userid`
SET userprofile.ranking = test.newRank;

答案 1 :(得分:0)

这是最终为我工作的查询。 选择胡安的答案作为接受的答案,因为这是建议这样做的答案。

DROP TABLE IF EXISTS t1;

CREATE TABLE t1 AS
SELECT userprofile.userid, ranks.ranking FROM userprofile
            JOIN (SELECT p.userid,
                         IF(@last_rating<> p.rating,
                            @cur_rank := @cur_rank + @next_rank,
                            @cur_rank)  AS ranking,
                         IF(@last_rating= p.rating,
                            @next_rank := @next_rank + 1,
                            @next_rank := 1),
                         @last_rating:= p.rating
                    FROM userprofile p
                    JOIN (SELECT @cur_rank := 0, @last_rating:= -1, @next_rank := 1) r
                   ORDER BY  p.rating DESC
                  ) ranks ON (ranks.userid = userprofile.userid);

UPDATE userprofile JOIN t1 ON userprofile.userid = t1.userid
SET userprofile.ranking = t1.ranking;

DROP TABLE t1;