CREATE UNIQUE INDEX index_subscriptions_on_user_id_and_class_type_id_and_deleted_at
ON subscriptions
USING btree
(user_id, class_type_id, deleted_at);
This query proves that the constraint does not actually work:
SELECT id, user_id, class_type_id, deleted_at
FROM subscriptions;
This is the output:
Why is uniqueness not enforced?
One way to solve this problem is to create a partial index , Apply different rules to rows that contain and do not contain NULL:
CREATE UNIQUE INDEX ... ON subscriptions
(user_id, class_type_id) WHERE deleted_at IS NULL;
CREATE UNIQUE INDEX ... ON subscriptions
(user_id, class_type_id, deleted_at) WHERE deleted_at IS NOT NULL;
This is My constraints:
CREATE UNIQUE INDEX index_subscriptions_on_user_id_and_class_type_id_and_deleted_at
ON subscriptions
USING btree
(user_id, class_type_id, deleted_at);< /pre>This query proves that the constraint does not actually work:
SELECT id, user_id, class_type_id,deleted_at
FROM subscriptions;< p>This is the output:
Why is uniqueness not enforced?
The unique index in Postgres is based on the value equality, but NULL will never be equal to any value, including other NULLs. Therefore, any row with NULL deleted_at value is Unlike any other possible rows-so you can insert as many rows as you want.
One way to solve this problem is to create a partial index, applying different values to rows that contain and do not contain NULL Rules:
CREATE UNIQUE INDEX ... ON subscriptions
(user_id, class_type_id) WHERE deleted_at IS NULL;
CREATE UNIQUE INDEX. .. ON subscriptions
(user_id, class_type_id, deleted_at) WHERE deleted_at IS NOT NULL;