19

Here is my constraint:

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 the constraint is not actually working:

SELECT id, user_id, class_type_id,deleted_at
FROM subscriptions;

Here is the output:

enter image description here

Why is uniqueness not being enforced?

1

2 Answers 2

65

Unique indexes in Postgres are based on values being equal, but NULL is never equal to anything, including other NULLs. Therefore any row with a NULL deleted_at value is distinct from any other possible row - so you can insert any number of them.

One way around this is to create partial indexes, applying different rules to rows with and without NULLs:

 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;
Sign up to request clarification or add additional context in comments.

Comments

8

This happens because of the NULL value in the created_at column. A unique index (or constraint) allows multiple rows with NULL in them.

The only way you can prevent that is to either declare the column as NOT NULL in order to force a value for it, or reduce the unique columns to (user_id, class_type_id)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.