根据下表,如何在删除一行或多行后使用单个查询按顺序将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;
答案 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。对于错误信息感到抱歉,因为我没有看到标签。