2

我有一个名为 'winners' 的表格,其中包含 'id'、'category'、'score'、'rank' 列。

我需要更新我的表并在子类别 (category_id) 中指定一个排名,根据样本,该排名为 2,但将来可能会更多。

我发现的大多数答案都是基于 select 语句,这些语句只是倾向于输出表格视图,但我确实找到了一个非常好的“更新”答案(https://stackoverflow.com/a/2727239/4560380)特别是答案更新领带必须共享相同的排名。

样本

CREATE TABLE winners (
id int,
category_id int,
score double,
rank int
);

INSERT INTO winners VALUES 
(1, 1, 4.36, NULL),
(2, 1, 2.35, NULL),
(3, 1, 1.25, NULL),
(4, 2, 4.21, NULL),
(5, 2, 3.33, NULL),
(6, 1, 4.24, NULL),
(7, 1, 1.22, NULL),
(8, 1, 1.25, NULL),
(9, 2, 4.21, NULL),
(10, 2, 3.63, NULL);

+----------+-------------+-------+------+
|       id | category_id | score | rank |
+----------+-------------+-------+------+
|        1 |           1 |  4.36 |      |
|        2 |           1 |  2.35 |      |
|        3 |           1 |  1.25 |      |
|        4 |           2 |  4.21 |      |
|        5 |           2 |  3.33 |      |
|        6 |           1 |  4.24 |      |
|        7 |           1 |  1.22 |      |
|        8 |           1 |  1.25 |      |
|        9 |           2 |  4.21 |      |
|       10 |           2 |  3.63 |      |
+----------+-------------+-------+------+

当只有一个类别需要担心时,上面的链接答案非常适用于数据,但当有多个类别或子组要在其中进行排名时则不行。

我曾尝试在代码中添加 where 子句(第 8 行)

1. UPDATE   winners
2. JOIN     (SELECT  w.score,
3.                IF(@lastPoint <> w.score, 
4.                   @curRank := @curRank + 1, 
5.                   @curRank)  AS rank,
6.                @lastPoint := w.rating
7.      FROM      winners w
8.      WHERE category_id = 1
9.      JOIN      (SELECT @curRank := 0, @lastPoint := 0) r
10.     ORDER BY  w.score DESC
11.     ) ranks ON (ranks.score = winners.score)
12. SET winners.rank = ranks.rank;

试图为每个 category_id 运行代码两次,但脚本失败。

为多个类别修改上述答案的任何选项都很棒。

需要的结果只是为了澄清(在类别中排名)。

+----------+-------------+-------+------+
|       id | category_id | score | rank |
+----------+-------------+-------+------+
|        1 |           1 |  4.36 |    1 |
|        6 |           1 |  4.24 |    2 |
|        2 |           1 |  2.35 |    3 |
|        8 |           1 |  1.25 |    4 |
|        3 |           1 |  1.25 |    4 |
|        7 |           1 |  1.22 |    5 |
|        4 |           2 |  4.21 |    1 |
|        9 |           2 |  4.21 |    1 |
|       10 |           2 |  3.63 |    2 |
|        5 |           2 |  3.33 |    3 |
+----------+-------------+-------+------+

多谢你们!

更新

设法找到另一段代码https://stackoverflow.com/a/13270603/4560380,我最初以某种方式错过了它,并且能够成功地使用每个 category_id 的 where 子句对其进行修改。这不是一种理想的方式 - 为多个类别运行多次,但此时它很好。

set @currentRank = 0,
@lastRating = null,
@rowNumber = 1;
update winners r
inner join (
    select
        score,
        @currentRank := if(@lastRating = score, @currentRank, @rowNumber) rank,
        @rowNumber := @rowNumber + if(@lastRating = score, 0, 1) rowNumber,
        @lastRating := score
    from winners
    where category_id = 1
    order by score desc
) var on var.score = r.score
set r.rank = var.rank

在 1 个脚本运行中对排名中的多个类别进行更“自动”处理的进一步答案仍然非常受欢迎和赞赏。

谢谢

更新

只是注意到我找到的答案不能很好地处理零分数(0.00),并将它们排在其他分数的中间。

下面的 shawnt00 答案正在工作并正确评估零分数。 https://stackoverflow.com/a/34667112/4560380

4

1 回答 1

0
update winners
set rank = (
    select count(score) + 1
    from winners w2
    where w2.category_id = winners.category_id and w2.score > winners.score
)

count(*)即使没有行匹配条件,即最高排名,也会评估为零。如果你想要一个密集的等级,你可以这样做:

update winners
set rank = (
    select count(distinct score) + 1
    from winners w2
    where w2.category_id = winners.category_id and w2.score > winners.score
)

编辑:根据您的评论,我发现了一个有效的查询。(它适用于 SQL Server,我不熟悉 MySQL 的怪癖。)http://sqlfiddle.com/#!9/1159f/1

update winners
inner join (
    select w.id, w.category_id, count(w2.score) + 1 rank
    from winners w left outer join winners w2
        on w2.category_id = w.category_id and w2.score > w.score
    group by w.id
) r
    on r.id = winners.id
set winners.rank = r.rank
于 2016-01-07T23:33:55.243 回答