mysql - 具有唯一约束的原子多行更新

标签 mysql sql postgresql sql-update

我有一个按排名顺序显示的标签表。为了确保没有两行可以具有相同的排名,它们的值是唯一的:

create table label (
  id_label serial not null,
  rank integer not null,
  title text not null,
  constraint pri primary key (id_label),
  constraint unq unique (rank)
)

不管是 PostgreSQL 还是 MySQL,它们都表现出相同的行为。查询可能类似于 select title from label order by rank。假设表包含:

id_label rank title
1        10   Cow
2        20   Apple
3        45   Horse
4        60   Beer

现在假设我想重新排序两个标签,例如苹果排在牛之前。最简单的方法是交换他们的排名值:

update label
set rank = case when rank = 20 then 10 else 20 end
where id_label in (1,2)

不。也不:

update label
set rank = case when rank = 20 then rank - 10 else rank + 10 end
where id_label in (1,2)

甚至:

update label
set rank = 30 - rank
where id_label in (1,2)

每次,唯一约束都会在第一行更新时触发并中止操作。如果我可以将支票推迟到声明结束时,我会很好。这在 PostgreSQL 和 MySQL 上都会发生。

酸安全的解决方法是:

  1. 开始交易
  2. 选择表中第一条、第二条记录和最高(最大)排名的排名(这可能需要一个联合)
  3. 将第一条记录更新为 rank = max + 1
  4. 将第二条记录更新为第一条
  5. 将第一条记录更新为第二条
  6. 提交

简直丑到无法形容。更糟糕的是删除约束,更新,然后重新创建约束。将此类特权授予操作角色是自找麻烦。所以我的问题是:有没有一种我忽略的简单技术可以解决这个问题,或者我是 SOL?

最佳答案

对于 PostgreSQL,这只能使用版本 9.0 以“很好”的方式解决,因为您可以在那里定义可延迟的唯一约束。

使用 PostgreSQL 9.0,您只需执行以下操作:

create table label (
  id_label serial not null,
  rank integer not null,
  title text not null,
  constraint pri primary key (id_label)
);
alter table label add constraint unique_rank unique (rank) 
      deferrable initially immediate;

那么更新就这么简单:

begin;
set constraints unique_rank DEFERRED;
update rank
   set rank = case when rank = 20 then 10 else 20 end
   where id_label in (1,2);
commit;

编辑:
如果您不想在事务中将约束设置为 deferred,您可以简单地将约束定义为 initially deferred

关于mysql - 具有唯一约束的原子多行更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5403437/

相关文章:

php - 如何在 php 中动态地将图像从 mysql 数据库插入到 jquery slider 中

php - 在 Grocery 店上传视频

sql - 带日期时间参数的ms sql调用存储过程

sql - 如何从时间戳表中每小时选择一行数据?

postgresql - 执行动态交叉表查询

postgresql - 将 SELECT 的结果连接到 EXECUTE

mysql - Spring mvc + hibernate + 列表中的 IN 子句

c# - 在C#中执行mysqldatareader时为"The given key was not present in the dictionary"

mysql - 挑战!复杂的 MySQL 查询

php - 网站使用的语言