我有一个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 |
+--------+--------+--------+---------+
答案 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;