![](/img/trans.png)
[英]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.