IS NULL, IS NOT NULL и безопасное сравнение с NULL
Правильно проверяйте NULL и используйте безопасные для NULL операторы в разных диалектах.
«IS NULL, IS NOT NULL и безопасное сравнение с NULL» — бесплатный урок Coding Interview Prep на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Coding Interview Prep, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Coding Interview Prep содержит 4 уроков всего.
Правильная проверка на NULL
В предыдущем уроке было доказано, что для поиска NULL нельзя использовать =. Как же проверять их на самом деле? С помощью специальных условий IS NULL и IS NOT NULL.
Это единственный корректный и переносимый способ проверить наличие отсутствующих значений, и на собеседовании у Вас всегда забракуют col = NULL.
В этом уроке рассматриваются IS NULL, IS NOT NULL, семейство IS DISTINCT FROM и зависящие от диалекта операторы сравнения на равенство с безопасной обработкой NULL. Знание различий между СУБД — сильный признак высокого уровня.
IS NULL и IS NOT NULL
IS NULL возвращает TRUE, когда значение равно NULL, и FALSE в противном случае. Важно, что это условие никогда не возвращает UNKNOWN, поэтому его безопасно использовать непосредственно в WHERE.
IS NOT NULL — его точное логическое дополнение: TRUE для любого фактического значения и FALSE для NULL.
Эти условия — основные инструменты обработки NULL. Они входят в стандарт SQL и одинаково работают в MySQL, Postgres, SQL Server, Oracle и SQLite.
-- Find employees with no recorded bonus
SELECT name FROM employees WHERE bonus IS NULL;
-- Find employees that do have a bonus
SELECT name FROM employees WHERE bonus IS NOT NULL;Почему col = NULL всегда неверно
Гарантированная ловушка на собеседовании: кандидат пишет WHERE bonus = NULL, ожидая найти бонусы, которых нет. Запрос возвращает ноль строк.
Вспомните трёхзначную логику: bonus = NULL даёт UNKNOWN для каждой строки, в том числе для строк со значением NULL, поскольку неизвестное значение ни с чем нельзя считать равным. WHERE сохраняет только TRUE, поэтому ничего не совпадает.
Некоторые базы данных в нестандартных режимах незаметно переписывают = NULL в IS NULL, но никогда не полагайтесь на это. Всегда явно записывайте IS NULL.
-- WRONG: returns zero rows, bonus = NULL is UNKNOWN for all
SELECT name FROM employees WHERE bonus = NULL;
-- RIGHT:
SELECT name FROM employees WHERE bonus IS NULL;Подсчёт значений NULL и не-NULL
Распространённая задача аналитика — проверка качества данных: насколько заполнен столбец? Объедините IS NULL с COUNT, чтобы вывести количество отсутствующих значений.
Обратите внимание на различие: COUNT(*) считает каждую строку, а COUNT(bonus) — только бонусы, не равные NULL. Разница между ними равна количеству NULL; к этому факту мы вернёмся в уроке об агрегатах.
SELECT
COUNT(*) AS total_rows,
COUNT(bonus) AS with_bonus,
COUNT(*) - COUNT(bonus) AS missing_bonus,
SUM(CASE WHEN bonus IS NULL THEN 1 ELSE 0 END) AS missing_check
FROM employees;Какую проблему решает безопасное для NULL сравнение на равенство
Предположим, Вы хотите сопоставить два столбца и считать совпадением случай, когда оба значения равны NULL. Обычное a = b не подходит: когда оба значения равны NULL, результатом становится UNKNOWN, поэтому пара исключается, хотя интуитивно значения кажутся «одинаковыми».
Это возникает при сравнении старой строки с новой для обнаружения изменений или при соединении по необязательным столбцам. Вам нужно сравнение, при котором NULL = NULL даёт TRUE, а NULL и значение дают FALSE. Именно это и обеспечивает безопасное для NULL сравнение на равенство.
-- Goal: change-detection where two NULLs count as equal
-- Plain equality fails when both sides are NULL:
-- NULL = NULL -> UNKNOWN (treated as not-equal)
SELECT * FROM old_t o JOIN new_t n ON o.id = n.id
WHERE o.note = n.note; -- misses rows where both notes are NULLIS DISTINCT FROM (стандартный SQL)
Стандартное ANSI-сравнение с безопасной обработкой NULL — это IS DISTINCT FROM и его обратная форма IS NOT DISTINCT FROM. Они поддерживаются в Postgres, SQL Server (начиная с версии 2022) и других СУБД.
a IS NOT DISTINCT FROM bозначает «равно; NULL = NULL считается равенством».a IS DISTINCT FROM bозначает «отличается; NULL считается обычным значением».
Эти условия всегда возвращают TRUE или FALSE, но никогда не UNKNOWN, поэтому безопасны везде, где требуется условие.
-- TRUE when notes match, including both NULL
SELECT * FROM old_t o JOIN new_t n ON o.id = n.id
WHERE o.note IS NOT DISTINCT FROM n.note;
-- TRUE when notes differ (NULL vs value counts as different)
SELECT * FROM old_t o JOIN new_t n ON o.id = n.id
WHERE o.note IS DISTINCT FROM n.note;Оператор <=> в MySQL
В MySQL есть компактный оператор сравнения с безопасной обработкой NULL, записываемый как <=> (оператор «космический корабль»).
a <=> b возвращает 1 (TRUE), если обе стороны равны или обе имеют значение NULL, и 0 (FALSE) в противном случае. Это эквивалент IS NOT DISTINCT FROM в MySQL.
Если на собеседовании Вас спрашивают именно о сравнении с безопасной обработкой NULL в MySQL, это будет идиоматичный ответ.
-- MySQL: 1 when both equal or both NULL
SELECT (NULL <=> NULL) AS both_null, -- 1
(NULL <=> 5) AS null_vs_val, -- 0
(5 <=> 5) AS val_eq; -- 1
SELECT * FROM old_t o JOIN new_t n ON o.id = n.id
WHERE o.note <=> n.note;Шпаргалка по различиям между диалектами
Интервьюеры ценят кандидатов, которые знают границы переносимости. Вот таблица сравнений с защитой от NULL:
- ANSI / Postgres / SQL Server 2022+:
IS NOT DISTINCT FROM - MySQL / MariaDB:
<=> - SQLite:
ISиIS NOTработают как сравнение на равенство с защитой от NULL - Oracle: нативного оператора нет; его можно имитировать с помощью
DECODE(a, b, 1, 0) = 1или приёмов с COALESCE
Если вы не уверены, какая СУБД используется, примените показанную далее переносимую ручную форму.
-- SQLite NULL-safe equality
SELECT * FROM t WHERE a IS b; -- TRUE when both NULL
SELECT * FROM t WHERE a IS NOT b; -- complementПереносимое ручное сравнение с защитой от NULL
Если нативный оператор недоступен, сравнение с защитой от NULL можно построить из базовых операций. Переносимый шаблон объединяет обычное сравнение на равенство с явным условием для случая, когда оба значения равны NULL.
Читайте это так: «они равны, OR оба отсутствуют». Это работает в любой СУБД, поэтому это отличный ответ, когда интервьюер не уточняет диалект.
SELECT *
FROM old_t o JOIN new_t n ON o.id = n.id
WHERE (o.note = n.note)
OR (o.note IS NULL AND n.note IS NULL);
-- Alternative using COALESCE with a sentinel that
-- cannot occur in real data:
-- WHERE COALESCE(o.note, '##NULL##') = COALESCE(n.note, '##NULL##')Более подробный пример: ключи JOIN с защитой от NULL
Типичная ловушка: соединение по ключу, допускающему NULL. Если region может быть равен NULL с обеих сторон, обычное соединение по равенству незаметно исключает такие пары, потому что NULL = NULL даёт UNKNOWN.
Если бизнес-правило гласит: «строки без региона всё равно должны сопоставляться с другими строками без региона», условие соединения нужно сделать безопасным для NULL. На собеседовании озвучьте это допущение, а затем выберите оператор, соответствующий СУБД.
-- Postgres / ANSI: match including both-NULL regions
SELECT a.id, b.id
FROM table_a a
JOIN table_b b
ON a.region IS NOT DISTINCT FROM b.region;
-- MySQL equivalent: ON a.region <=> b.regionОсновные тезисы для собеседования
Чтобы уверенно отвечать на любой вопрос о проверке NULL:
- Всегда используйте
IS NULL/IS NOT NULL; никогда не используйте= NULL. - Эти предикаты возвращают только TRUE или FALSE, поэтому безопасны в WHERE.
- Для сопоставления «NULL равен NULL» используйте IS NOT DISTINCT FROM (ANSI) или <=> (MySQL).
- Укажите, для какого диалекта пишется запрос; если вы не уверены, предложите переносимый вариант с условием OR.
Упоминание стандартного и поставляемого разработчиком оператора демонстрирует широту знаний, которую отмечают специалисты по первичному отбору.
Быстрая проверка
Выберите правильное сравнение с защитой от NULL.
Итоги
Теперь вы умеете правильно проверять NULL:
IS NULL/IS NOT NULL— единственные корректные переносимые проверки NULL; они никогда не возвращают UNKNOWN.col = NULLвсегда возвращает ноль строк; это классическая ловушка на собеседовании.- Сравнение с защитой от NULL считает два значения NULL равными: IS NOT DISTINCT FROM (ANSI/Postgres), <=> (MySQL), IS (SQLite).
- Если подходящего оператора нет, используйте
(a = b) OR (a IS NULL AND b IS NULL).
Далее: замена NULL значениями по умолчанию с помощью COALESCE, NULLIF и функций конкретных СУБД, таких как ISNULL.
Часто задаваемые вопросы
Урок «IS NULL, IS NOT NULL и безопасное сравнение с NULL» бесплатный?
Да — полный текст урока «IS NULL, IS NOT NULL и безопасное сравнение с NULL» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Coding Interview Prep, подпишись на CoddyKit PRO. Курс Coding Interview Prep содержит 4 уроков всего.
Чему я научусь в уроке «IS NULL, IS NOT NULL и безопасное сравнение с NULL»?
Правильно проверяйте NULL и используйте безопасные для NULL операторы в разных диалектах. Ты практикуешь Coding Interview Prep с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Coding Interview Prep?
Предыдущий опыт не требуется. Coding Interview Prep на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «IS NULL, IS NOT NULL и безопасное сравнение с NULL»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Coding Interview Prep?
Да. Каждый урок Coding Interview Prep включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Трёхзначная логика и UNKNOWN
- IS NULL, IS NOT NULL и безопасное сравнение с NULL
- COALESCE, NULLIF и ISNULL
- NULL в агрегатах, объединениях и DISTINCT