2017-05-30 218 views
2

所以我有一個表類似的結構:試圖UPSERT一個表部分索引

CREATE TABLE x (
    id SERIAL, 
    a character varying(1024) NOT NULL, 
    b character varying(2048), 
    c character varying(1024) 
); 

CREATE UNIQUE INDEX uniq_x_a ON x USING btree (a) WHERE (b IS NULL); 
CREATE UNIQUE INDEX uniq_x_a_b ON x USING btree (a, b) WHERE (b IS NOT NULL); 

現在我升級這種情況下,以9.5和要使用的ON CONFLICT DO UPDATE

所以執行這個

INSERT INTO x (a, b, c) VALUES ('hello', 'there', 'c1'); 
INSERT INTO x (a, b, c) VALUES ('hello', 'there', 'c2'); 

現在給我

ERROR: duplicate key value violates unique constraint "uniq_x_a_b" 
DETAIL: Key (a, b)=(hello, there) already exists. 

後來,當我做

INSERT INTO x (a, b, c) VALUES ('hello', 'there', 'c4') 
ON CONFLICT ON CONSTRAINT uniq_x_a_b DO UPDATE SET c = excluded.c; 

我得到

ERROR: constraint "uniq_x_a_b" for table "x" does not exist 

我不明白,我違反了一個不存在的約束?任何人都有小費?

編輯

每我加

ALTER TABLE x ADD CONSTRAINT uniq_x_a_b_constraint UNIQUE (a, b); 

所以這個現在適用於以下幾種情況下建議:

INSERT INTO x (a, b, c) VALUES ('hello', 'there', 'c3') 
ON CONFLICT ON CONSTRAINT uniq_x_a_b_constraint DO UPDATE SET c = excluded.c; 

但失敗了

INSERT INTO x (a, b, c) VALUES ('hello', NULL, 'c3') 
ON CONFLICT ON CONSTRAINT uniq_x_a_b_constraint DO UPDATE SET c = excluded.c; 

ERROR: duplicate key value violates unique constraint "uniq_x_a" 
DETAIL: Key (a)=(hello) already exists. 

我不能單獨a列添加一個唯一約束,因爲它是被認爲是唯一的ab組合。似乎也不可能像創建索引一樣在行的子集上構建約束。

回答

2

這裏有一些東西在玩。

  1. 創建唯一索引不會自動創建一個唯一約束(儘管術語constraint錯誤消息在使用時你想插入重複記錄)。另一方面,添加唯一約束將自動在列或列組上創建唯一的B樹索引(請參閱此doc)。

  2. 不同於常規指標的情況下,限制不能使用的部分索引補充說:

    ALTER TABLE x ADD CONSTRAINT uniq_x_a_constraint UNIQUE USING INDEX uniq_x_a; 
    ERROR: "uniq_x_a" is a partial index ... 
    DETAIL: Cannot create a primary key or unique constraint using such an index. 
    

在本質上,你需要在(a, b)(無關創建一個單獨的唯一約束部分索引)以便以預期的方式生成ON CONFLICT函數。

[更新]

即使a和b的組合是唯一的,ON CONFLICT將不會看到任何有效的約束強制唯一性:

INSERT INTO x (a, b, c) VALUES ('hello', 'there', 'c4') 
ON CONFLICT (a, b) DO UPDATE SET c = excluded.c; 
ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification 

現在,如果你添加約束,既ON CONFLICT (a, b)ON CONFLICT ON CONSTRAINT將工作:

ALTER TABLE x ADD CONSTRAINT uniq_x_a_b_constraint UNIQUE (a, b); 

INSERT INTO x (a, b, c) VALUES ('hello', 'there', 'c4') 
ON CONFLICT (a, b) DO UPDATE SET c = excluded.c; 

INSERT INTO x (a, b, c) VALUES ('hello', 'there', 'c5') 
ON CONFLICT ON CONSTRAINT uniq_x_a_b_constraint DO UPDATE SET c = excluded.c; 
+0

a和b的組合應該是唯一的,只有b可以包含NULL值。 – Jan

+0

@Jan,請參閱我的擴展答案。 –

+0

是的,但是這在'INSERT INTO x(a,b,c)VALUES('hello',NULL,'c3')上失敗ON CONFLICT ON CONSTRAINT uniq_x_a_b_constraint DO UPDATE SET c = excluded.c;' – Jan