I have a table like this:
CREATE TABLE "users"
(
id serial PRIMARY KEY,
town text NOT NULL,
street text not null,
building text
);
I want to be able to store unique entries by 3 columns "town", "street" and "building". If the third row "building" is null, there should be impossible to store any new other rows with same "town" or "street" column, no matter what is in the column "building".
So this should work:
---- example 1:
INSERT INTO "users" ("town", "street", "building") VALUES ('t', 's', 8);
INSERT INTO "users" ("town", "street", "building") VALUES ('t', 's', 9);
---- example 2:
INSERT INTO "users" ("town", "street", "building") VALUES ('t', 's', null);
But this should not:
---- example 1:
INSERT INTO "users" ("town", "street", "building") VALUES ('t', 's', 8);
INSERT INTO "users" ("town", "street", "building") VALUES ('t', 's', 9);
INSERT INTO "users" ("town", "street", "building") VALUES ('t', 's', null);
---- example 2:
INSERT INTO "users" ("town", "street", "building") VALUES ('t', 's', 8);
INSERT INTO "users" ("town", "street", "building") VALUES ('t', 's', 8);
I tried to use two partial indexes for this:
CREATE UNIQUE INDEX "two_cols"
ON "users" ("town", "street")
WHERE "building" IS NULL;
CREATE UNIQUE INDEX "three_cols"
ON "users" ("town", "street", "building")
WHERE "building" IS NOT NULL;
but the problem that you can only set filter for current index, so first index only checks inside their query, and this allows to store null value with other values, which is not what I need. Removing filter on first index disallow to store two rows with same two but different third column. Is there an option to solve this problem?
Your first INSERT with twi the same data, fails and because both are treated as one transaction, and a roll back happen, which erases both insert.
this you can see as the second insert works perfectly. the builng 8 is not proesent.
when you make every insert its own transaction, it will enter the row and the second is no problem as it is in its own transaction, which when it rolls back, has 7 already saved.
so in short use transactions
fiddle