According to the docs ,
All unique table_name indexes, which, regardless of order, contain exactly the columns / expressions specified in the context_target parameter, are displayed (selected) as arbitration indexes. If index_predicate is specified, it, as an additional requirement for output, must satisfy the arbiter indices.
Documents keep saying
[index_predicate] used to enable partial unique indexes
In an underestimated form, the documents say that when using a partial index and adding with ON CONFLICT, you must specify index_predicate . This is not displayed for you. I found out about it here , and the following example demonstrates this.
CREATE TABLE test.accounts ( id int PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, type text, person_id int); CREATE UNIQUE INDEX accounts_note_idx on accounts (type, person_id) WHERE ((type)::text = 'PersonAccount'::text); INSERT INTO test.accounts (type, person_id) VALUES ('PersonAccount', 10);
so we have:
unutbu=# select * from test.accounts; +----+---------------+-----------+ | id | type | person_id | +----+---------------+-----------+ | 1 | PersonAccount | 10 | +----+---------------+-----------+ (1 row)
Without index_predicate we get an error:
INSERT INTO test.accounts (type, person_id) VALUES ('PersonAccount', 10) ON CONFLICT (type, person_id) DO NOTHING; -- ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
But if instead you include index_predicate, WHERE ((type)::text = 'PersonAccount'::text) :
INSERT INTO test.accounts (type, person_id) VALUES ('PersonAccount', 10) ON CONFLICT (type, person_id) WHERE ((type)::text = 'PersonAccount'::text) DO NOTHING;
then there is no mistake, and NOTHING is observed.