Недавно я заметил несоответствие в том, как Postgres обрабатывает NULL в столбцах с уникальным ограничением.
Рассмотрим таблицу людей:
create table People (
pid int not null,
name text not null,
SSN text unique,
primary key (pid)
);
Столбец SSN должен быть уникальным. Мы можем проверить, что:
-- 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');
Вторая вставка завершается неудачно, поскольку она нарушает ограничение уникальности для SSN. Все идет нормально. Но давайте попробуем NULL:
insert into People(pid, name, SSN)
values(1, 'Carol', null);
Это работает.
select *
from People;
0;"Bob";"123"
1;"Carol";"<NULL>"
Уникальный столбец примет нулевое значение. Интересно. Как Postgres может утверждать, что null в любом случае уникален или не уникален в этом отношении?
Интересно, могу ли я добавить две строки с нулем в уникальный столбец.
insert into People(pid, name, SSN)
values(2, 'Ted', null);
select *
from People;
0;"Bob";"123"
1;"Carol";"<NULL>"
2;"Ted";"<NULL>"
Да, я могу. Теперь в столбце SSN есть две строки с NULL, хотя номер SSN должен быть уникальным.
В документации Postgres говорится, В целях уникального ограничения нулевые значения не считаются равными.
Хорошо. Я вижу смысл этого. Это хорошая тонкость в обработке нулей: рассматривая все NULL в столбце с уникальными ограничениями как непересекающиеся, мы откладываем принудительное применение уникального ограничения до тех пор, пока не будет фактического ненулевого значения, на котором можно основать это принудительное применение.
Это довольно круто. Но здесь Postgres теряет меня. Если все NULL в столбце с уникальными ограничениями не равны, как сказано в документации, то мы должны увидеть все нули в select различном запросе.
select distinct SSN
from People;
"<NULL>"
"123"
Неа. Там только один ноль. Похоже, у Postgres это неправильно. Но мне интересно: есть ли другое объяснение?
Редактировать:
Документы Postgres указывают, что «нулевые значения считаются равными в этом сравнении». в разделе на SELECT DISTINCT . Хотя я не понимаю этого понятия, я рад, что оно изложено в документации.