[英]MySQL: Avoid having to set a NULL value on an UNIQUE field before updating it
我有一个 SQL 表,其中包含两个字段: id
和order
。
CREATE TABLE IF NOT EXISTS article (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`order` INT(11) UNIQUE,
PRIMARY KEY (`id`)
);
在这张表中,我有一些项目:
+----+-------+
| id | order |
+----+-------+
| 1 | 0 |
| 2 | 1 |
| 3 | 2 |
| 4 | 3 |
| 5 | 4 |
| 6 | 5 |
| 7 | 6 |
| 8 | 7 |
| 9 | 8 |
| 10 | 9 |
+----+-------+
Now I want to change order position of one item: element with id 3 (order position 2) will move into position 6. Thus, the elements between position 4 and 6 (this last one included) will have to decrease their order
field. 结果应该是这样的:
+----+-------+
| id | order |
+----+-------+
| 1 | 0 |
| 2 | 1 |
| 4 | 2 | ⌉
| 5 | 3 | |
| 6 | 4 | | Updated items
| 7 | 5 | |
| 3 | 6 | ⌋
| 8 | 7 |
| 9 | 8 |
| 10 | 9 |
+----+-------+
当然,第一次更新——用order
字段6
更新 id 为3
的商品——很简单:
UPDATE article
SET article.order = 6
WHERE id = 1;
然后我可以减少位置大于 2 和低于或 euql 小于 6 之间的项目:
UPDATE article
SET article.order = article.order -1
WHERE
article.order > 2
AND
article.order <= 6
;
但是这里有一个问题: order
字段是UNIQUE
。 所以我必须首先将它设置为NULL
来移动我要移动的项目:
UPDATE article
SET article.order = NULL
WHERE id = 3;
UPDATE article
SET article.order = article.order -1
WHERE
article.order > 2
AND
article.order <= 6
;
UPDATE article
SET article.order = 6
WHERE id = 3;
有没有办法避免设置这个NULL
? 这是一个小提琴: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=342d714e88e68d3c4c6e0ca1ec8efa6c
它可以在 2 次更新中完成。
在一些变量的帮助下。
还有一种降序的否定形式。
--
-- move id 3 to position 6
--
SET @id := 3;
SET @orig := (select `order` from article where id = @id);
SET @dest := 6;
UPDATE article
SET `order` = NULL
WHERE id = @id;
UPDATE article
SET `order` =
case
when `order` between @orig and @dest then `order` - 1
when `order` is null then @dest
else `order`
end
WHERE (`order` is null OR `order` between @orig and @dest)
ORDER BY -`order` DESC;
关于db<>fiddle 的演示在这里
有没有办法避免设置这个 NULL?
不在 MySQL 中。 SQL 标准定义了解决此特定问题的可延迟约束的特性。 不幸的是,MySQL 没有实现 SQL 规范的这一部分。 Null 是您唯一的选择。
现在,当一个约束被标记为可延迟时(如在 PostgreSQL 或 Oracle 中),它的验证可以推迟到每个 SQL 语句执行结束,甚至整个事务结束; 也就是说,它的完整验证仅在commit
时发生,在所有更新都已完成并且所有值都会再次良好之后。
如您所见,除非您可以选择迁移到 PostgreSQL 或 Oracle(极不可能),否则您将无法使用空值。
我会问自己是否真的需要唯一约束? 是否有任何功能依赖于唯一的订单价值? 约束的额外开销是否必要? 如果不 -
UPDATE `article`
SET `order` = IF(`id` = 3, 6, `order` - 1)
WHERE `order` BETWEEN 2 AND 6;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.