Почему уникальное поле в PostgreSQL может содержать несколько NULL

Запрет повторов и обязательность заполнения — отдельные правила. Объясняем на простом примере, как PostgreSQL проверяет уникальность при неизвестном значении.

Оранжевый шар и три пустых керамических кольца на графитовой подставке.

Уникальность ещё не означает заполненность

Представим условный каталог оборудования. У каждого предмета есть внутренняя карточка, а заводской номер заполняют после приёмки. Команда хочет запретить два одинаковых известных заводских номера, но разрешить создать несколько карточек до завершения проверки. Поэтому формулировка «поле уникальное» оставляет важный вопрос: что делать, пока номер неизвестен?

В SQL, языке работы с данными, отсутствие известного значения может обозначаться NULL. Это специальный признак, который нужно отличать от числа ноль и от записанной строки нулевой длины. Базовый смысл разобран в статье об отсутствии значения. Здесь рассмотрим более узкую задачу: какое правило повторов действует, когда такие пропуски встречаются в поле с ограничением уникальности.

В PostgreSQL важно выбранное поведение проверки

Согласно документации PostgreSQL об ограничениях, при стандартном поведении два NULL не считаются равными для проверки уникальности. Поэтому уникальное поле может содержать несколько строк с таким признаком. Это не означает, что база установила различие между неизвестными заводскими номерами: она применяет определённое правило контроля.

Для нашего каталога это подходит на этапе приёмки: известный номер не должен повторяться, а несколько ещё не проверенных предметов могут существовать одновременно. Но назвать такую настройку безусловно правильной нельзя. Если по смыслу проекта допускается лишь одна незаполненная карточка, необходимо отдельно выразить именно это требование и согласовать его с владельцем процесса.

Запрет пропусков задаётся отдельно

В той же документации обязательность значения описана самостоятельным ограничением. Можно потребовать и заполненность, и отсутствие повторов. Тогда наш каталог должен будет получать заводской номер до сохранения карточки либо использовать другой порядок приёмки. Это решение меняет рабочий процесс, поэтому его нельзя принимать только по названию технического ограничения.

Предложим для обсуждения три вымышленные карточки: у первой номер известен, у двух других он ещё не установлен. При допустимых пропусках все три могут храниться одновременно. При обязательном заполнении две карточки потребуют дополнительных действий. В обоих случаях надо отдельно ответить, может ли повториться уже известный номер. Эти вопросы удобно обсуждать раздельно, чтобы не спрятать одно требование внутри другого.

У составного правила есть дополнительная тонкость

Иногда уникальность относится к сочетанию нескольких полей. В нашем примере заводской номер может проверяться вместе с производителем: разные производители используют собственную нумерацию. В описании уникальных индексов PostgreSQL указано, что проверка нескольких столбцов отклоняет повтор, когда совпадают все проверяемые значения. Поведение пропусков при этом тоже имеет значение.

PostgreSQL позволяет выбрать режим, в котором NULL для такой проверки рассматриваются как равные. Синтаксис здесь не нужен: важно уметь поставить вопрос специалисту о фактически выбранном режиме. Не переносите предположение из одного проекта в другой. Документация отдельно предупреждает, что поведение неизвестных значений при уникальности может различаться между системами управления базами данных.

Проверять нужно смысл, а затем настройку

Для нашего каталога подготовим небольшой список ожидаемых случаев: повтор известного номера, два неизвестных номера, одинаковый номер у разных производителей, изменение пропуска на уже занятый номер. Рядом запишем желаемый результат каждого случая словами. Такой список не требует программирования и помогает обнаружить расхождение между договорённостью команды и фактической моделью хранения.

Уникальное поле само по себе не гарантирует, что две карточки относятся к разным физическим предметам. Для устойчивой связи записей полезно понимать назначение ключей. Продолжить знакомство с правилами хранения и проверки данных можно на курсе «SQL инженер». Начните с короткого требования: какие значения обязательны, какие повторы запрещены и что означает неизвестность в вашей задаче.

SQL инженер
Курс
Доступ сразу
SQL инженер

SQL инженер — это специалист, который работает с базами данных, разрабатывает запросы, оптимизирует хранение данных и обеспечивает эффективную работу с информацией в компаниях.

С нуля до junior
Теория и практика
Диплом по окончании
500
₽/мес
УЗНАТЬ ПОДРОБНЕЕ

Источники

Читайте также

Обучить команду или нанять специалиста по данным: как выбрать
61

Обучить команду или нанять специалиста по данным: как выбрать

Как руководителю определить, какие навыки развивать внутри команды, когда нужна новая роль и почему обучение и найм часто дополняют друг друга.
Вертикальное и горизонтальное масштабирование данных: в чём разница
62

Вертикальное и горизонтальное масштабирование данных: в чём разница

Когда системе добавляют мощность одного сервера, когда делят работу между несколькими и почему увеличение ресурсов само по себе не решает любую проблему.
Журнал изменений данных: как выяснить, кто и когда изменил набор
60

Журнал изменений данных: как выяснить, кто и когда изменил набор

Что можно узнать из журнала действий с данными, как он помогает разбирать ошибки и почему его записи не показывают всю историю сами по себе.

Занятия проходят
в Нова Дата СДО

Вебинары, практика и общение с преподавателем — в одном окне браузера.

Посмотреть интерфейс платформы
Календарь обучения в Нова Дата СДО
Курсы студента в Нова Дата СДО
Редактор кода для практики в Нова Дата СДО
Вебинары и расписание Ваши курсы Код в браузере
Нова Дата СДО — в реестре российского ПОРеестровая запись № 34931
Заявка отправлена
Отправим вам подборку курсов в течение 5 минут. С вами также свяжется наш специалист и даст карьерную консультацию.
Персональный промокод
На курс «Инженер по парсингу данных»
Введите код при оплате, чтобы применить скидку к программе.