[英]PostgreSQL partial unique index and upsert
我正在嘗試對具有部分唯一索引的表進行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;
簡單來說, p
不是null,只有q
或r
可以為null。
重復插入會按預期拋出約束違規
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
但是,當我嘗試使用唯一約束進行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
它仍然會引發約束違規
錯誤:重復鍵值違反唯一約束“test_pr_idx”DETAIL:鍵(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, ''));
現在所有三個測試(執行兩次)都違反了相同的索引:
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
在insert命令中,您應該傳遞索引定義中使用的表達式:
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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.