Недавно я заметил несогласованность в том, как 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>"
Уникальный столбец примет значение null. Интересно. Как Postgres утверждают, что нуль никоим образом не уникален или не уникален в этом отношении?
Интересно, могу ли я добавить две строки с нулевым значением в уникальный столбец.
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 distinct SSN
from People;
"<NULL>"
"123"
Неа. Там только один пустой. Похоже, Postgres это неправильно. Но мне интересно: есть ли еще одно объяснение?
Изменить:
В документах Postgres указано, что "значения Null считаются равными в этом сравнении". в разделе на SELECT DISTINCT. Хотя я не понимаю этого понятия, я рад, что это указано в документах.