MySQL 更新排名的查询
MySQL query to update ranking
我有一个 mysql table,其中包含 userid、rating 和 ranking 作为字段。 table 很大(>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
这是查询前 table 的示例
+--------+--------+-----+------+------------+--------+--------------+---------+---------------+
| 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 语句,它会在 ranks.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)
Select 查询的结果
+--------+--------+--------+---------+
| 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 |
+--------+--------+--------+---------+
你能创建一个时间 table,然后执行更新吗?
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;
这是最终对我有用的查询。
选择 Juan 的答案作为接受的答案,因为它是建议这样做的答案。
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;
我有一个 mysql table,其中包含 userid、rating 和 ranking 作为字段。 table 很大(>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
这是查询前 table 的示例
+--------+--------+-----+------+------------+--------+--------------+---------+---------------+
| 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 语句,它会在 ranks.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)
Select 查询的结果
+--------+--------+--------+---------+
| 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 |
+--------+--------+--------+---------+
你能创建一个时间 table,然后执行更新吗?
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;
这是最终对我有用的查询。 选择 Juan 的答案作为接受的答案,因为它是建议这样做的答案。
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;