2010-07-20 19 views
1

這是一個玩具示例,說明了PostgreSQL中的一個實際問題。下面的例子是使用PostgreSQL 8.4.3服務器,但我懷疑其他版本也有同樣的問題。在PostgreSQL中更新非空和唯一約束的列的特例

如下表:

 
=> create table tmp_foo (foo boolean not null unique, bar boolean not null unique); 
=> insert into tmp_foo (foo, bar) values (true, true), (false, false); 
=> select * from tmp_foo; 
foo | bar 
-----+----- 
t | t 
f | f 

可以將表進行修改,看起來像這樣:

 
=> select * from tmp_foo; 
foo | bar 
-----+----- 
t | f 
f | t 

而不刪除行或修改表模式?此:

 
=> update tmp_foo set bar = not bar; 
ERROR: duplicate key value violates unique constraint "tmp_foo_bar_key" 

不起作用。

如果刪除是允許的,這一點:

 
=> create temp table tmp_foo_2 as select * from tmp_foo; 
=> update tmp_foo_2 set bar = not bar; 
=> delete from tmp_foo; 
=> insert into tmp_foo select * from tmp_foo_2; 

作品。這個例子並不是最簡單的解決方案,但它可以很容易地推廣到更復雜的例子。

+0

這是一個有趣的問題,但我不明白爲什麼你不想在那裏刪除。你已經創建了一個非常呃約束的約束集。你試圖解決的更大的問題是什麼? – Charles 2010-07-20 22:44:47

回答

3

這樣做需要可延遲的唯一約束。

我們有儘可能多的行在每個列中的唯一值。因此,要突變任何行,某些行必須暫時違反唯一約束,或者必須刪除一些行以避免違反約束。可延遲的唯一約束讓我們做前者 - 臨時違規(在交易中)。

如果您追蹤到目前爲止,並且聽起來不錯,那麼您的問題的答案取決於Postgres版本。

Postgres最多8.4只allows deferral of foreign key constraints。推論是獨特的約束不能推遲。

Postgres 9.0 beta在理論上提供可延遲的唯一約束。我自己並沒有嘗試過,但是這個功能已經很久了,所以我敢打賭,當他們決定實施它時,他們是對的。

這裏有兩個關於9.0的unique indicesSET CONSTRAINTS的文件。正如您在後面的鏈接中看到的那樣,在9.0文檔中通過SET CONSTRAINTS明確列出了唯一的約束條件,作爲延期支持。我還沒有探索這個新功能,我不能保證語義正是你所需要的。但它似乎只是一件事。

+1

+1 - 良好的工作指出9.0新功能。 – rfusca 2010-07-21 00:59:43