在一个查询中的每一行中增加一个唯一列

问题描述 投票:0回答:3

我正在尝试更新包含两列的表;

id
position
id
是唯一的并且自动递增。
position
是唯一的,但不会自动递增,实际上必须手动设置。

我需要更改位置大于或等于

5
(或我提供的任何其他数字)的所有行,将它们全部加一。这是我的代码:

UPDATE slides 
SET   position = position + 1 
WHERE position >= 5;

不幸的是,它返回以下错误:

错误:键“slides_position_unique”的条目“2”重复

如何更新所有这些唯一编号而不引起冲突?我尝试过使用子查询来查找所有可更新的行并反向返回它们,但这没有帮助。


CREATE TABLE slides
  (id int(10) unsigned NOT NULL AUTO_INCREMENT,
   user_id int(10) unsigned NOT NULL,
   position int(10) unsigned NOT NULL,
   PRIMARY KEY (id),
   UNIQUE KEY slides_position_unique (position),
   KEY slides_user_id_foreign (user_id),
   CONSTRAINT slides_user_id_foreign
     FOREIGN KEY (user_id) REFERENCES users (id) )
mysql sql select sql-update auto-increment
3个回答
5
投票

您可以在更新中使用 order by 。正如mysql doc事实:

如果指定了 ORDER BY 子句,则按顺序更新行 指定的

这会导致:

UPDATE slides 
SET   position = position + 1 
WHERE position >= 5
ORDER BY position DESC;

通过这种方式,您可以先更新更大的值,然后更新更大的 1,然后更新更大的 2,等等...并且唯一索引在分配给下一行之前始终会被释放。

请注意,根据您的用例,如果其他脚本需要同时访问此数据,您可能需要使用行锁定或表锁定来避免竞争条件。


3
投票

问题在于唯一约束——更新期间值不是唯一的。您可以在事务中执行此操作或删除约束然后添加它:

ALTER TABLE slides DROP index slides_position_unique;
UPDATE slides SET position = position + 1 WHERE position >= 1;
ALTER TABLE slides ADD CONSTRAINT  slides_position_unique UNIQUE (position);

请参阅 http://sqlfiddle.com#!9/66e0d8 了解工作示例。


0
投票

错误非常明显:应用此查询会产生重复的行。为了避免这种情况,请更改您的查询。我想这意味着要么删除

WHERE position >= 1
(以更新所有行),要么添加另一个条件来排除
slides.position < 1

也许这个更简单的查询适合您:

UPDATE slides 
SET   position = position + 1 
WHERE position >= 1 AND position IS NOT NULL

您可能会使用

UPDATE IGNORE slides set position = position+1
但这可能会让您丢失一些行。

© www.soinside.com 2019 - 2024. All rights reserved.