PostgreSQL partial unique index and upsert PostgreSQL partial unique index and upsert postgresql postgresql

PostgreSQL partial unique index and upsert


I don't think it's possible to use multiple partial indexes as a conflict target. You should try to achieve the desired behaviour using a single index. The only way I can see is to use a unique index on expressions:

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, ''));

Now all three tests (executed twice) violate the same index:

insert into test(p,q,r,txt) values ('p',null,null,'a'); -- violates test_unique_idxinsert into test(p,q,r,txt) values ('p','q',null,'b');  -- violates test_unique_idxinsert into test(p,q,r,txt) values ('p',null, 'r','c'); -- violates test_unique_idx

In the insert command you should pass the expressions used in the index definition:

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;