Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Postgres handle NULLs inconsistently where unique constraints are involved?

Tags:

People also ask

Does unique constraint allow NULL values Postgres?

While the SQL standard allows multiple nulls in a unique column, and that is how Postgres behaves, some database systems (e.g. MS SQL) allow only a single null in such cases.

Does unique constraint allow nulls?

You can insert NULL values into columns with the UNIQUE constraint because NULL is the absence of a value, so it is never equal to other NULL values and not considered a duplicate value.

Why one should use the unique key if it allows only one NULL?

Solution 1. Logically, any key which is allowed to contain non duplicate (unique) values is a unique key, NULL is a permissible value in sql server , so it can have NULL for a single time just like any other value.

Can Unique Key have multiple nulls?

There are way to create a unique index that allows multiple nulls in MS SQL Server, but it's not the default. The default in MS is to allow just one NULL. But that's not the ANSI standard. ANSI standards 92, 99, and 03 explicitly allow multiple nulls with unique.


I recently noticed an inconsistency in how Postgres handles NULLs in columns with a unique constraint.

Consider a table of people:

create table People (
   pid  int  not null,
   name text not null,
   SSN  text unique,
 primary key (pid)
);

The SSN column should be kept unique. We can check that:

-- Add a row.
insert into People(pid, name, SSN)
values(0, 'Bob', '123');

-- Test the unique constraint.
insert into People(pid, name, SSN)
values(1, 'Carol', '123');

The second insert fails because it violates the unique constraint on SSN. So far, so good. But let's try a NULL:

insert into People(pid, name, SSN)
values(1, 'Carol', null);

That works.

select *    
from People;

0;"Bob";"123"
1;"Carol";"<NULL>"

A unique column will take a null. Interesting. How can Postgres assert that null is in any way unique, or not unique for that matter?

I wonder if I can add two rows with null in a unique column.

insert into People(pid, name, SSN)
values(2, 'Ted', null);

select *    
from People;

0;"Bob";"123"
1;"Carol";"<NULL>"
2;"Ted";"<NULL>"

Yes I can. Now there are two rows with NULL in the SSN column even though SSN is supposed to be unique.

The Postgres documentation says, For the purpose of a unique constraint, null values are not considered equal.

Okay. I can see the point of this. It's a nice subtlety in null-handling: By considering all NULLs in a unique-constrained column to be disjoint, we delay the unique constraint enforcement until there is an actual non-null value on which to base that enforcement.

That's pretty cool. But here's where Postgres loses me. If all NULLs in a unique-constrained column are not equal, as the documentation says, then we should see all of the nulls in a select distinct query.

select distinct SSN
from People;

"<NULL>"
"123"

Nope. There's only a single null there. It seems like Postgres has this wrong. But I wonder: Is there another explanation?


Edit:

The Postgres docs do specify that "Null values are considered equal in this comparison." in the section on SELECT DISTINCT. While I do not understand that notion, I'm glad it's spelled out in the docs.