所以我的表格结构类似于:
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
上添加唯一约束,因为它是a
和b
的组合,应该是唯一的。似乎也不可能在行的子集上构建约束,就像创建索引一样。
答案 0 :(得分:2)
这里有几件事情在发挥作用。
创建唯一索引不会自动创建唯一约束(尽管在尝试插入重复记录时,错误消息中使用了术语constraint
)。另一方面,添加唯一约束将自动在列或列组上创建唯一的B树索引(请参阅此doc)。
与常规索引不同,无法使用部分索引添加约束:
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
起作用。
[UPDATE]
即使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;