cin*_*ata 7 sql postgresql unique upsert
经过谷歌搜索后,我的问题描述如下:
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;
Run Code Online (Sandbox Code Playgroud)
试图插入值:
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;
Run Code Online (Sandbox Code Playgroud)
结果是:
[42P10] ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
Run Code Online (Sandbox Code Playgroud)
Altho这个工作(按规格):
insert into security (vendor, external_id, extinct)
values('Legion', 'LGNONE', false)
ON CONFLICT DO NOTHING;
Run Code Online (Sandbox Code Playgroud)
PostgreSQL v9.5
我的目标是找到在多个可空列上在此表上创建唯一索引的方法,并在UPSERT上使用新行更新旧行
kli*_*lin 12
在conflict_target使用中on conflict必须标识现有唯一索引.你不能使用
on conflict (vendor, external_id, extinct)
Run Code Online (Sandbox Code Playgroud)
因为三列上没有索引.Postgres结合多个索引以满足您的冲突目标并不是那么聪明.
但是,您可以像这样创建一个部分索引:
create unique index unique_vendor_external_id
on security(vendor, external_id, extinct)
where coalesce(vendor, external_id) is not null;
Run Code Online (Sandbox Code Playgroud)
现在您可以将这三列用作冲突目标:
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
Run Code Online (Sandbox Code Playgroud)
注意使用特殊记录excluded.对于文档:
ON CONFLICT DO UPDATE中的SET和WHERE子句可以使用表的名称(或别名)访问现有行,并使用特殊排除表访问建议插入的行.