Как обсуждалось в других ответах, NULL предназначался для обозначения «информация, которая должна идти в этом столбце, неизвестна».Тем не менее, также часто используется для обозначения альтернативного значения «этот атрибут не существует».Это особенно полезная интерпретация при просмотре полей меток времени, которые интерпретируются как время, когда произошло определенное событие, и в этом случае NULL часто используется для указания того, что событие еще не произошло.
Проблема в том, чтоSQL не очень хорошо поддерживает эту интерпретацию - для правильной работы ей нужно иметь отдельное значение (что-то вроде «никогда»), которое не ведет себя как ноль («никогда» должно быть равно «никогда»"и должен сравниваться как выше, чем все другие значения).Но поскольку в SQL отсутствует это понятие, и нет удобного способа его добавить, использование для этого цели обычно является нулевым.
Это оставляет проблему, когда при отметке времени события, которое могло не произойтидолжен быть частью первичного ключа таблицы (обычным требованием, возможно, является использование естественного ключа вместе с меткой времени удаления при использовании мягкого удаления с требованием для возможности воссоздания элемента после удаления), вам действительно нужен первичный ключиметь обнуляемый столбец.Увы, это недопустимо в большинстве баз данных, и вместо этого вам приходится прибегать к искусственному первичному ключу (например, порядковому номеру строки) и уникальному ограничению того, что в противном случае должно было бы быть вашим действительным первичным ключом.
AnПример сценария, чтобы уточнить это: у меня есть таблица users
.Поскольку я требую, чтобы у каждого пользователя было отдельное имя пользователя, я решил использовать username
в качестве первичного ключа.Я хочу поддерживать удаление пользователей, но так как мне необходимо исторически отслеживать существование пользователей для целей аудита, я использую мягкое удаление (в первой версии схемы я добавляю флаг «удаленный» для пользователя и гарантирую, что удаленныйфлаг отмечен во всех запросах, где ожидаются только активные пользователи).
Однако дополнительное требование заключается в том, что если имя пользователя удалено, оно должно быть доступно для регистрации новым пользователям.Привлекательным способом для достижения этой цели было бы изменить флаг удаления на временную метку, которая может иметь значение NULL (где нули указывают, что пользователь не был удален) и поместить ее в первичный ключ.Если бы первичные ключи допускали пустые столбцы, это имело бы следующий эффект:
- Создание нового пользователя с существующим именем пользователя, когда столбец этого пользователя
deleted
равен нулю, будет отклонено как запись дублированного ключа - Удаление пользователя изменяет его ключ (который требует каскадных изменений для внешних ключей, которые ссылаются на пользователя, что является неоптимальным, но допустимо редкое удаление), так что столбец
deleted
является меткой времени, когдапроизошло удаление - Теперь можно успешно создать нового пользователя (который будет иметь нулевую
deleted
метку времени).
Однако на самом деле этого нельзя достичь стандартным SQL, поэтому вместо этогонеобходимо использовать другой первичный ключ (возможно, сгенерированный числовой идентификатор пользователя в этом случае) и использовать ограничение UNIQUE для обеспечения уникальности (username
, deleted
).