按顺序更新mysql表

时间:2018-06-12 12:28:25

标签: mysql sql sequential

根据下表,如何在删除一行或多行后使用单个查询按顺序将position从1重新排序为N,并保持position的顺序?

+---------+----------+-----+
| id (pk) | position | fk  |
+---------+----------+-----+
|       4 |        1 | 123 |
|       2 |        2 | 123 |
|      18 |        3 | 123 |
|       5 |        4 | 123 |
|       3 |        5 | 123 |
+---------+----------+-----+

例如,如果删除position = 1(id = 4),则所需的最终记录为:

+---------+----------+-----+
| id (pk) | position | fk  |
+---------+----------+-----+
|       2 |        1 | 123 |
|      18 |        2 | 123 |
|       5 |        3 | 123 |
|       3 |        4 | 123 |
+---------+----------+-----+

如果删除position = 3(id = 18),则所需的最终记录为:

+---------+----------+-----+
| id (pk) | position | fk  |
+---------+----------+-----+
|       4 |        1 | 123 |
|       2 |        2 | 123 |
|       5 |        3 | 123 |
|       3 |        4 | 123 |
+---------+----------+-----+

如果只删除了行而不是多行,我可以执行以下操作。

DELETE FROM mytable WHERE fk=123 AND position = 4;
UPDATE mytable SET position=position-1 WHERE fk=123 AND position > 4;

2 个答案:

答案 0 :(得分:4)

User-defined variables如果您还没有使用MySQL 8,它提供了像ROW_NUMBER()这样的窗口函数,那么就可以解决问题:

UPDATE t
JOIN (

    SELECT 
    t.*
    , @n := @n + 1 as n
    FROM t
    , (SELECT @n := 0) var_init
    ORDER BY position

) sq ON t.id = sq.id
SET t.position = sq.n;

<强>奖金:

当你有多个小组时,它会变得稍微复杂一些 例如,对于像这样的样本数据

|  id | position |  fk |
|-----|----------|-----|
|   4 |        1 | 123 |
|   2 |        2 | 123 |
|   5 |        4 | 123 |
|   3 |        5 | 123 |
|  40 |        1 | 234 |
|  20 |        2 | 234 |
| 180 |        3 | 234 |
|  30 |        5 | 234 |

查询将是

UPDATE t
JOIN (

    SELECT 
    t.*
    , @n := if(@prev_fk != fk, 1, @n + 1) as n
    , @prev_fk := fk
    FROM t
    , (SELECT @n := 0, @prev_fk := NULL) var_init
    ORDER BY fk, position

) sq ON t.id = sq.id
SET t.position = sq.n;

在这里,您只需将当前fk保存在另一个变量中。处理下一行时,变量仍保留&#34;前一行&#34;的值。然后在值更改时重置@n变量。

<强>更新

在MySQL 8中,你可以像这样使用窗口函数row_number()

update t join (
    select t.*, row_number() over (partition by fk order by position) as new_pos 
    from t
) sq using (id) set t.position = sq.new_pos;

答案 1 :(得分:1)

您可以使用更新和ROW_NUMBER()功能。如果您按位置订购,那就应该没问题。

UPDATE [1]
SET POSITION = [2].RN
FROM t [1]
JOIN (
       SELECT 
           t.ID
           , ROW_NUMBER() OVER (ORDER BY POSITION DESC) AS RN
       FROM t
     ) [2] 
ON [1].id = [2].id

正如人们所说,这不适用于MySql。对于错误信息感到抱歉,因为我没有看到标签。