ubi*_*ubi 6 postgresql unique upsert
我正在尝试对具有部分唯一索引的表进行更新插入
create table test (
p text not null,
q text,
r text,
txt text,
unique(p,q,r)
);
create unique index test_p_idx on test(p) where q is null and r is null;
create unique index test_pq_idx on test(p, q) where r IS NULL;
create unique index test_pr_idx on test(p, r) where q is NULL;
Run Code Online (Sandbox Code Playgroud)
通俗地说,p不为空,只有一个q或r可以为空。
重复插入会按预期抛出约束违规
insert into test(p,q,r,txt) values ('p',null,null,'a'); -- violates test_p_idx
insert into test(p,q,r,txt) values ('p','q',null,'b'); -- violates test_pq_idx
insert into test(p,q,r,txt) values ('p',null, 'r','c'); -- violates test_pr_idx
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试对 upsert 使用唯一约束时
insert into test as u (p,q,r,txt) values ('p',null,'r','d')
on conflict (p, q, r) do update
set txt = excluded.txt
Run Code Online (Sandbox Code Playgroud)
它仍然抛出约束违规
错误:重复键值违反唯一约束“test_pr_idx”详细信息:键 (p, r)=(p, r) 已经存在。
但我希望该on conflict条款能够捕获它并进行更新。
我究竟做错了什么?我应该使用index_predicate?
index_predicate 用于允许推断部分唯一索引。可以推断出满足谓词的任何索引(实际上不必是部分索引)。遵循 CREATE INDEX 格式。 https://www.postgresql.org/docs/9.5/static/sql-insert.html
我认为不可能使用多个部分索引作为冲突目标。您应该尝试使用单个索引来实现所需的行为。我能看到的唯一方法是在表达式上使用唯一索引:
drop table if exists test;
create table test (
p text not null,
q text,
r text,
txt text
);
create unique index test_unique_idx on test (p, coalesce(q, ''), coalesce(r, ''));
Run Code Online (Sandbox Code Playgroud)
现在所有三个测试(执行两次)都违反了相同的索引:
insert into test(p,q,r,txt) values ('p',null,null,'a'); -- violates test_unique_idx
insert into test(p,q,r,txt) values ('p','q',null,'b'); -- violates test_unique_idx
insert into test(p,q,r,txt) values ('p',null, 'r','c'); -- violates test_unique_idx
Run Code Online (Sandbox Code Playgroud)
在插入命令中,您应该传递索引定义中使用的表达式:
insert into test as u (p,q,r,txt)
values ('p',null,'r','d')
on conflict (p, coalesce(q, ''), coalesce(r, '')) do update
set txt = excluded.txt;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3032 次 |
| 最近记录: |