dla*_*and 12 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)
)
Run Code Online (Sandbox Code Playgroud)
无论是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
Run Code Online (Sandbox Code Playgroud)
现在假设我想重新排序两个标签,例如让Apple排在Cow之前.最简单的方法是交换他们的等级值:
update label
set rank = case when rank = 20 then 10 else 20 end
where id_label in (1,2)
Run Code Online (Sandbox Code Playgroud)
不.也不:
update label
set rank = case when rank = 20 then rank - 10 else rank + 10 end
where id_label in (1,2)
Run Code Online (Sandbox Code Playgroud)
甚至不是:
update label
set rank = 30 - rank
where id_label in (1,2)
Run Code Online (Sandbox Code Playgroud)
每次,唯一约束触发第一行更新并中止操作.如果我可以将支票推迟到声明结束,我会没事的.这种情况发生在PostgreSQL和MySQL上.
ACID安全的解决方法是:
这简直难以置信.更糟糕的是删除约束,更新,然后重新创建约束.授予操作角色这样的权限是一件麻烦事.所以我的问题是:有一种我忽略的简单技术可以解决这个问题,还是我是SOL?
小智 6
对于 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;
Run Code Online (Sandbox Code Playgroud)
那么更新就这么简单:
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;
Run Code Online (Sandbox Code Playgroud)
编辑:
如果您不想在事务中将约束设置为 deferred,您可以简单地将约束定义为initially deferred。
| 归档时间: |
|
| 查看次数: |
2443 次 |
| 最近记录: |