[英]Syntax of a multi-row update that updates specific rows with unique information
[英]Atomic multi-row update with a unique constraint
我有一个按排名顺序显示的标签表。 为确保没有两行可以具有相同的排名,它们的值是唯一的:
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
现在假设我想重新排序两个标签,例如让Apple排在Cow之前。 最简单的方法是交换他们的等级值:
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上。
ACID安全的解决方法是:
这简直难以置信。 更糟糕的是删除约束,更新,然后重新创建约束。 授予操作角色这样的权限是一件麻烦事。 所以我的问题是:有一种我忽略的简单技术可以解决这个问题,还是我是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;
编辑:
如果您不想在事务中将约束设置为延迟,则可以简单地将约束定义为initially deferred
。
我有类似的问题,我的解决方案如下:
START TRANSACTION
SELECT * FROM label WHERE id_label IN(1,2)
Delete FROM label WHERE id_label IN(1,2)
INSERT INTO label(all, columns, of, table) VALUES(all, values, we, selected)
COMMIT TRANSACTION
如果有任何错误,回滚事务。
您可以执行此操作而不删除唯一约束。
当然你可以:
update label set rank = 5 where id_label=2
但是我想这里的问题是你需要能够处理连续排名之间没有“差距”的情况。 对于postgres,使用numeric
而不是integer
来解决问题,因为它具有几乎无限的精度
create table label (
id_label serial not null,
rank numeric not null,
title text not null,
constraint pri primary key (id_label),
constraint unq unique (rank)
)
现在你只需更新一行就可以将它移动到排名中的任何位置,无论任何其他行的排名如何,都可以通过分割上面的等级和下面的等级之间的差异来实现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.