Трёхзначная логика и UNKNOWN
Узнайте, почему NULL = NULL не является истинным и как UNKNOWN распространяется по условиям.
«Трёхзначная логика и UNKNOWN» — бесплатный урок Coding Interview Prep на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Coding Interview Prep, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Coding Interview Prep содержит 4 уроков всего.
Почему NULL сбивает кандидатов
NULL — главная причина неправильных ответов на собеседованиях по SQL. Ловушка заключается в том, что его принимают за обычное значение, хотя на самом деле NULL означает «неизвестно» или «отсутствует», а не ноль и не пустую строку.
На собеседованиях любят этот вопрос, потому что синтаксис выглядит правильным, но результат оказывается незаметно неверным. Вам могут показать фильтр, который «должен» вернуть строку, и спросить, почему он ничего не возвращает.
В этом уроке Вы сформируете модель мышления, которая поможет ответить на любой вопрос о NULL: трёхзначную логику. Как только Вы поймёте, что сравнения могут возвращать TRUE, FALSE или UNKNOWN, всё остальное станет очевидным.
NULL — не значение
Самая важная фраза, которую стоит сказать на собеседовании: NULL — это отсутствие значения, а не самостоятельное значение.
Поэтому его нельзя сравнивать с помощью = так же, как числа. База данных не знает, равны ли два неизвестных значения, и поэтому не может однозначно выбрать между TRUE и FALSE.
NULL = 5— это не FALSE, а UNKNOWNNULL = NULL— это не TRUE, а UNKNOWNNULL <> NULLтакже даёт UNKNOWN
Именно поэтому наивный фильтр равенства по столбцу, допускающему NULL, незаметно исключает строки.
Двухзначная и трёхзначная логика
В большинстве языков программирования используется двухзначная логика: выражение бывает либо TRUE, либо FALSE. SQL добавляет третий результат — UNKNOWN, когда в сравнении участвует NULL.
Таким образом, любое условие в SQL может вычисляться в один из трёх результатов: TRUE, FALSE или UNKNOWN. Предложение WHERE сохраняет строку только тогда, когда её условие даёт ровно TRUE. Для фильтрации UNKNOWN ведёт себя как FALSE, но с точки зрения логики это не одно и то же.
На собеседованиях проверяют, знаете ли Вы это различие, потому что под действием NOT UNKNOWN ведёт себя не так, как FALSE.
Фильтр, который незаметно исключает строки
Рассмотрим классический пример с разбором. Предположим, что bonus иногда имеет значение NULL. Рекрутер спрашивает: «Этот запрос должен вернуть всех, чей бонус не равен 1000. Почему он пропускает сотрудников без бонуса?»
Для строки, где bonus равен NULL, выражение bonus <> 1000 вычисляется как UNKNOWN, а не TRUE. WHERE сохраняет только строки со значением TRUE, поэтому такие сотрудники исчезают из результата.
Исправление заключается в явной обработке NULL, которую мы рассмотрим в следующем уроке. А пока важно понять: пропавшие строки — это результат работы логики, а не ошибка.
SELECT name, bonus
FROM employees
WHERE bonus <> 1000;
-- Rows where bonus IS NULL are excluded:
-- NULL <> 1000 evaluates to UNKNOWN, not TRUENULL в выражениях AND
Трёхзначная логика меняет поведение AND. Запомните это правило — и Вы сможете сразу ответить на любой вопрос по таблице истинности.
- TRUE AND UNKNOWN = UNKNOWN
- FALSE AND UNKNOWN = FALSE
- UNKNOWN AND UNKNOWN = UNKNOWN
Логика такова: AND достаточно одного FALSE, чтобы результат был однозначно FALSE. Поэтому FALSE AND что угодно остаётся FALSE. Но TRUE AND неизвестное значение по-прежнему даёт неизвестный результат, поскольку неизвестная сторона может оказаться как TRUE, так и FALSE.
-- If status = 'active' is TRUE but bonus = 100 is UNKNOWN:
SELECT *
FROM employees
WHERE status = 'active' AND bonus = 100;
-- Combined result is UNKNOWN, so the row is NOT returnedNULL в выражениях OR
OR работает зеркально по отношению к AND. Ему достаточно одного TRUE, чтобы результат был однозначно TRUE, поэтому TRUE устраняет влияние UNKNOWN.
- TRUE OR UNKNOWN = TRUE
- FALSE OR UNKNOWN = UNKNOWN
- UNKNOWN OR UNKNOWN = UNKNOWN
Таким образом, строка всё ещё может соответствовать условию с OR, даже если одна ветвь даёт неизвестный результат, при условии что другая ветвь действительно даёт TRUE. Это частый дополнительный вопрос после задачи про AND.
SELECT *
FROM employees
WHERE department = 'Sales' OR bonus = 100;
-- A Sales employee with NULL bonus:
-- TRUE OR UNKNOWN = TRUE, so the row IS returnedNOT меняет TRUE и FALSE, но не UNKNOWN
Это тонкий момент, который интервьюеры обычно оставляют напоследок. NOT превращает TRUE в FALSE, а FALSE — в TRUE, но NOT UNKNOWN по-прежнему даёт UNKNOWN.
Именно поэтому нельзя просто обернуть не сработавшее условие в NOT, чтобы изменить результат. Если для строки с NULL выражение bonus = 1000 даёт UNKNOWN, то NOT (bonus = 1000) тоже даёт UNKNOWN, и строка по-прежнему исключается.
Отрицание не возвращает строки с NULL. Для этого нужна явная проверка IS NULL.
-- For a row where bonus IS NULL:
-- bonus = 1000 -> UNKNOWN
-- NOT (bonus = 1000) -> UNKNOWN (still excluded)
SELECT * FROM employees WHERE NOT (bonus = 1000);Разобранный пример: ловушка NOT IN
Это одна из самых популярных задач о NULL. NOT IN со списком, содержащим NULL, не возвращает ни одной строки, что удивляет кандидатов, ожидающих, что NULL просто будет пропущен.
Внутри x NOT IN (1, 2, NULL) раскрывается в x <> 1 AND x <> 2 AND x <> NULL. Последнее сравнение даёт UNKNOWN, а TRUE AND TRUE AND UNKNOWN сводится к UNKNOWN, поэтому ни одна строка не проходит фильтр.
Безопасная альтернатива — NOT EXISTS, которая не подвержена этой проблеме.
-- Returns ZERO rows if the subquery yields any NULL
SELECT name
FROM employees
WHERE manager_id NOT IN (SELECT manager_id FROM managers);
-- Each comparison against NULL becomes UNKNOWN,
-- and the AND-chain collapses to UNKNOWN for every row.Почему UNKNOWN ведёт себя как FALSE в WHERE
Частый дополнительный вопрос: «Если UNKNOWN — это не FALSE, почему строка исключается так же, как строка со значением FALSE?»
Ответ точен: WHERE, ON и HAVING используют правило «оставлять только TRUE». И FALSE, и UNKNOWN не проходят эту проверку, поэтому при фильтрации они выглядят одинаково.
Различие проявляется только при отрицании и в ограничениях CHECK. Ограничение CHECK пропускает строку, если условие даёт TRUE или UNKNOWN, поэтому NULL может пройти проверку CHECK, которая, как Вы предполагали, должна была его заблокировать.
-- CHECK passes on TRUE or UNKNOWN, so NULL salary is allowed:
-- CONSTRAINT salary_positive CHECK (salary > 0)
-- INSERT ... salary = NULL -> NULL > 0 is UNKNOWN -> allowedБолее глубокий пример: COUNT и пробел в логике истинности
Свяжем всё это с реалистичной формулировкой с собеседования. «У нас 100 сотрудников. SELECT COUNT(*) WHERE bonus = 100 возвращает 30, а WHERE bonus <> 100 — 50. Куда делись остальные 20?»
У 20 пропавших сотрудников бонус имеет значение NULL. Ни = 100, ни <> 100 не дают для них TRUE — оба выражения дают UNKNOWN, поэтому эти строки не проходят ни один из фильтров.
Фраза «категории не дают в сумме общее количество, потому что NULL не удовлетворяет ни одному из условий» — именно тот ответ, который хотят услышать на собеседовании.
SELECT
COUNT(*) FILTER (WHERE bonus = 100) AS eq_100,
COUNT(*) FILTER (WHERE bonus <> 100) AS ne_100,
COUNT(*) FILTER (WHERE bonus IS NULL) AS null_bonus,
COUNT(*) AS total
FROM employees;Что сказать на собеседовании
Когда речь заходит о логике NULL, упомяните следующие моменты, чтобы продемонстрировать высокий уровень:
- NULL означает неизвестное значение; сравнения с ним дают UNKNOWN.
- SQL использует трёхзначную логику: TRUE, FALSE, UNKNOWN.
- WHERE, ON и HAVING сохраняют только TRUE-строки.
NOT UNKNOWNпо-прежнему даёт UNKNOWN, поэтому отрицание не возвращает строки с NULL.NOT INс любым NULL не возвращает строк; предпочитайтеNOT EXISTS.
Сначала изложите модель, а затем пройдите по таблице истинности. Такой порядок показывает, что Вы понимаете причину, а не просто запомнили приём.
Быстрая проверка
Проверьте, насколько хорошо Вы понимаете трёхзначную логику.
Итоги
Теперь у Вас есть ключевая модель мышления о NULL:
- NULL — это неизвестное значение, а не значение; никогда не сравнивайте его с помощью
=или<>. - SQL использует трёхзначную логику: условия возвращают TRUE, FALSE или UNKNOWN.
- Условия фильтрации сохраняют только TRUE; строки с UNKNOWN исчезают так же, как строки с FALSE.
NOTменяет TRUE на FALSE и FALSE на TRUE, но оставляет UNKNOWN без изменений.- Ловушка
NOT IN+ NULL возвращает ноль строк; используйтеNOT EXISTS.
Далее Вы узнаете, как правильно проверять NULL с помощью IS NULL, IS NOT NULL и операторов сравнения с безопасной обработкой NULL.
Часто задаваемые вопросы
Урок «Трёхзначная логика и UNKNOWN» бесплатный?
Да — полный текст урока «Трёхзначная логика и UNKNOWN» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Coding Interview Prep, подпишись на CoddyKit PRO. Курс Coding Interview Prep содержит 4 уроков всего.
Чему я научусь в уроке «Трёхзначная логика и UNKNOWN»?
Узнайте, почему NULL = NULL не является истинным и как UNKNOWN распространяется по условиям. Ты практикуешь Coding Interview Prep с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Coding Interview Prep?
Предыдущий опыт не требуется. Coding Interview Prep на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Трёхзначная логика и UNKNOWN»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Coding Interview Prep?
Да. Каждый урок Coding Interview Prep включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Трёхзначная логика и UNKNOWN
- IS NULL, IS NOT NULL и безопасное сравнение с NULL
- COALESCE, NULLIF и ISNULL
- NULL в агрегатах, объединениях и DISTINCT