Можно ли в составной ключ включить поле с NULL
Что проверяют
Различаете ли вы первичный ключ и уникальное ограничение и знаете ли, как база сравнивает NULL. Тестировщику это нужно, чтобы находить дубли, которые схема пропустила. Следом часто просят написать запрос, который такие дубли найдёт.
Как отвечать
Ответ зависит от вида ключа:
- первичный ключ: нельзя. По стандарту SQL все колонки PK неявно
NOT NULL, так ведут себя PostgreSQL, MySQL, SQL Server и Oracle. PostgreSQL и MySQL при создании ключа сами делают колонкиNOT NULL, а вставка NULL падает с ошибкой; - уникальный составной ключ (
UNIQUE (a, b)): можно, но поведение различается. В PostgreSQL и MySQL NULL не равен NULL, поэтому строки(1, NULL)и(1, NULL)обе запишутся. В SQL Server и Oracle вторая такая строка нарушит ограничение. В PostgreSQL с 15 версии это настраивается:UNIQUE NULLS NOT DISTINCT; - составной внешний ключ: в режиме по умолчанию
MATCH SIMPLEстрока, где хотя бы одна колонка FK равна NULL, не проверяется вовсе. Можно записать(999, NULL), хотя родителя с 999 нет.
Как тестировать: посмотреть DDL (\d имя_таблицы в psql, SHOW CREATE TABLE в MySQL), вставить две строки с одинаковыми значениями и NULL в одной из колонок, поискать дубли запросом с GROUP BY a, b HAVING count(*) > 1. Учтите, что GROUP BY складывает NULL в одну группу, а WHERE b = NULL не найдёт ничего, нужно IS NULL.
Где спотыкаются
Говорят «NULL в ключе можно, просто это плохо». Для первичного ключа это неверно: ни одна распространённая СУБД так сделать не даст.
Уверены, что UNIQUE гарантирует отсутствие дублей в бизнес-смысле. С nullable-колонкой две «одинаковые» записи спокойно живут рядом, и баг всплывает уже в отчётах.
Переносят поведение одной базы на другую. Тест, зелёный на PostgreSQL, упадёт на SQL Server, если приложение поддерживает обе.