依次更新mysqltable
Sequentially update mysql table
鉴于以下 table,我如何在删除一个或多个行后使用单个查询按顺序将 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;
如果您还没有使用 MySQL 8,User-defined variables 来拯救它,它提供 window 函数,例如 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;
- 看到它在 sqlfiddle
中实时运行
奖金:
当您有多个组时,情况会稍微复杂一些。
例如,对于这样的样本数据
| 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保存在另一个变量中。处理下一行时,该变量仍保留 "previous row" 的值。然后在值更改时重置 @n
变量。
- 看到它在 sqlfiddle
中实时运行
更新:
在 MySQL 8 中,您可以像这样使用 window 函数 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;
您可以使用更新和 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。抱歉,我没有看到标签,所以信息有误。
鉴于以下 table,我如何在删除一个或多个行后使用单个查询按顺序将 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;
User-defined variables 来拯救它,它提供 window 函数,例如 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;
- 看到它在 sqlfiddle 中实时运行
奖金:
当您有多个组时,情况会稍微复杂一些。
例如,对于这样的样本数据
| 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保存在另一个变量中。处理下一行时,该变量仍保留 "previous row" 的值。然后在值更改时重置 @n
变量。
- 看到它在 sqlfiddle 中实时运行
更新:
在 MySQL 8 中,您可以像这样使用 window 函数 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;
您可以使用更新和 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。抱歉,我没有看到标签,所以信息有误。