For starters you could have a partial UNIQUE index
CREATE UNIQUE INDEX table2_foo_idx ON table2 (value3, value2, table1_id)`
WHERE value3 IS NOT NULL;
Related:
But this does not account for duplicate values of value1
in table1
. This cannot be enforced with a constraint without dirty tricks, since all relevant constraints only involve columns of the same table.
There are various workarounds, depending on the complete situation. Triggers, a partial functional unique multicolumn index using a fake immutable function, a (NOT VALID
) CHECK
constraint ...
One clean way to enforce this is to store value1
in table2
redundantly, add multicolumn FK constraint with ON UPDATE CASCADE
and create the unique index mentioned above:
CREATE TABLE table1 (
table1_id bigserial PRIMARY KEY
, value1 text NOT NULL
, UNIQUE (value1, table1_id) -- logically redundant, neede for FK
);
CREATE TABLE table2 (
table2_id bigserial PRIMARY KEY
, table1_id bigint NOT NULL
, value1 text NOT NULL
, value2 text NOT NULL
, value3 text
, FOREIGN KEY (table1_id, value1) REFERENCES table1(table1_id, value1) ON UPDATE CASCADE
);
CREATE UNIQUE INDEX table2_foo_idx ON table2 (value3, value2, value1)`
WHERE value3 IS NOT NULL;
Related:
Chose an opportune order of columns in your unique index and constraint to best support typical queries without adding more indexes. Compare: