经过谷歌搜索后,我的问题描述如下:
CREATE TABLE security (
id SERIAL PRIMARY KEY,
vendor VARCHAR(20),
external_id VARCHAR(20),
extinct BOOLEAN DEFAULT FALSE
);
CREATE UNIQUE INDEX unique_vendor ON security(vendor, extinct) where vendor is not null;
CREATE UNIQUE INDEX unique_external_id ON security(external_id, extinct) where external_id is not null;
尝试插入值:
insert into security (vendor, external_id, extinct)
values('Legion', 'LGNONE', false)
ON CONFLICT(vendor, external_id, extinct) DO UPDATE
SET vendor = 'Legion', external_id = 'LGNONE', extinct = false;
结果:
[42P10] ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
这可行(按规格):
insert into security (vendor, external_id, extinct)
values('Legion', 'LGNONE', false)
ON CONFLICT DO NOTHING;
PostgreSQL documentation stands that it should work
PostgreSQL v9.5
我的目标是找到在多个可空列上在此表上创建唯一索引的方法,并在UPSERT上使用新行更新旧行
答案 0 :(得分:10)
on conflict
中使用的conflict_target
必须标识现有的唯一索引。你不能使用
on conflict (vendor, external_id, extinct)
因为三列上没有索引。 Postgres结合多个索引以满足您的冲突目标并不是那么聪明。
但是,您可以像这样创建一个部分索引:
create unique index unique_vendor_external_id
on security(vendor, external_id, extinct)
where coalesce(vendor, external_id) is not null;
现在您可以将这三列用作冲突目标:
insert into security (vendor, external_id, extinct)
values('Legion', 'LGNONE', false)
on conflict (vendor, external_id, extinct) -- exact match to the index definition
where coalesce(vendor, external_id) is not null -- obligatory index_predicate
do update set
vendor = excluded.vendor,
external_id = excluded.external_id,
extinct = excluded.extinct
请注意使用特殊记录excluded
。对于文档:
ON CONFLICT DO UPDATE中的SET和WHERE子句可以使用表的名称(或别名)访问现有行,并使用特殊的排除表来建议插入行。