根据查询设置排名

时间:2019-10-19 22:50:37

标签: mysql sql sql-update mysql-5.7

我有一个表格items,其中列出了idpopularityrank列中的不同元素。

popularity列包含一个int,可以按流行度对元素进行排序。

我已经查询了按受欢迎程度排序并为每个条目设置了排名:

SELECT id,
       @curRank := @curRank + 1 AS rank
FROM items, (SELECT @curRank := 0) r
ORDER BY popularity DESC

此查询运行良好,并给我一个idrank的结果,其中rank的值符合预期,并按popularity的顺序排列。

我想要实现的是为每个条目设置rank的值,我以此方式进行了尝试:

UPDATE items A
JOIN (
       SELECT id,
              @curRank := @curRank + 1 AS rank 
       FROM items, 
              (SELECT @curRank := 0) r 
       ORDER BY popularity DESC
      ) AS ranks
SET A.rank = ranks.rank 
WHERE A.id = ranks.id

为每行设置一个rank值,但不遵守ORDER BY popularity DESC。相反,排名值似乎是由id顺序设置的(​​id 1具有rank 1,id 2具有rank 2等)。 / p>

我在做什么错了?

此致

2 个答案:

答案 0 :(得分:3)

我认为您正在使这项工作变得比应做的要困难。

SET @curRank = 0;

UPDATE items
SET rank = (@curRank := @curRank+1)
ORDER BY popularity DESC;

我只是在UPDATE之前在SET语句中设置@curRank变量。当您尝试将它们组合在一起时,它只会使您的代码阅读者想知道这意味着什么。

您无需使它们成为同一语句的一部分。只要您在同一数据库会话中执行两个语句,会话变量将保持其值。

不需要子查询或联接。只需使用UPDATE ... ORDER BY(尽管如果确实需要执行JOIN操作,则在MySQL中无法使用ORDER BY进行UPDATE)。

答案 1 :(得分:1)

MySQL在处理变量和排序时具有令人惊讶的行为。

您可以 尝试的一件事是更早地进行订购,方法是将ORDER BY上的items移至子查询,如下所示:

UPDATE items A
JOIN (
       SELECT id,
              @curRank := @curRank + 1 AS rank 
       FROM 
            (SELECT id FROM items ORDER BY popularity DESC) items,
            (SELECT @curRank := 0) r 
      ) AS ranks
SET A.rank = ranks.rank 
WHERE A.id = ranks.id

Demo on DB Fiddle

数据:

| id  | popularity | rank |
| --- | ---------- | ---- |
| 1   | 1          | 1    |
| 2   | 2          | 2    |
| 3   | 3          | 3    |
| 4   | 4          | 4    |
| 5   | 5          | 5    |

更新后:

| id  | popularity | rank |
| --- | ---------- | ---- |
| 1   | 1          | 5    |
| 2   | 2          | 4    |
| 3   | 3          | 3    |
| 4   | 4          | 2    |
| 5   | 5          | 1    |