Отладка SQL: синтаксические, логические ошибки и ошибки с NULL
Содержание курса
NULL в условиях и агрегатах, стратегия отладки логических ошибок
Логическая ошибка с NULL коварна именно потому, что СУБД молчит: запрос выполняется без сообщений, но возвращает пустой результат или неправильное число.
Сравнение с NULL. Выражение column = NULL в SQL всегда даёт NULL — не TRUE и не FALSE. Это следствие трёхзначной логики: NULL означает «неизвестно», и результат сравнения неизвестного с чем угодно тоже неизвестен. WHERE отбирает строки только при TRUE, поэтому WHERE manager_id = NULL не отберёт ни одной строки — даже если в таблице полно строк с manager_id IS NULL. Правильная запись:
-- Неверно: всегда пусто
SELECT * FROM employees WHERE manager_id = NULL;
-- Верно
SELECT * FROM employees WHERE manager_id IS NULL;
Аналогично работает IS NOT NULL — для исключения строк с отсутствующим значением.
NULL в агрегатах. COUNT(*) считает все строки без исключения. COUNT(column) считает только строки, где column не NULL — строки с NULL в этом столбце пропускаются. Это приводит к неожиданным расхождениям:
SELECT
COUNT(*) AS total_rows,
COUNT(manager_id) AS rows_with_manager
FROM employees;
Если три сотрудника не имеют менеджера, total_rows будет больше rows_with_manager на три. SUM и AVG тоже игнорируют NULL: если все значения в столбце NULL, оба вернут NULL, а не 0.
Стратегия: три шага отладки. Когда запрос выполняется, но результат подозрительный, действуй последовательно.
Читай сообщение об ошибке — если оно есть, это первый и самый точный источник информации. Там указан тип и позиция проблемы.
-
Упрощай по частям. Убери JOIN, WHERE, GROUP BY — оставь только
SELECT ... FROM ...и проверь, работает ли базовая часть. Затем добавляй предложения по одному, пока проблема не проявится снова. Так ты изолируешь именно то место, которое ломает логику. -
Проверяй ожидаемое число строк. Если знаешь, сколько строк должно вернуться, сравни с фактическим:
SELECT COUNT(*) FROM ...с тем же WHERE. Пустой результат сам по себе не доказывает ошибку: фильтр, диапазон или JOIN могут законно не найти строк. Сначала проверьте ожидаемый результат на известных данных, затем по отдельности WHERE и условия JOIN. Если условие сравнивает nullable-столбец с NULL, отдельно ищите= NULLи заменяйте его наIS NULLилиIS NOT NULL.
Эти три шага работают в связке: синтаксические ошибки закрываются первым шагом, ошибки неоднозначности столбцов — тоже первым, а логические ошибки с NULL требуют второго и третьего, потому что СУБД на них не жалуется.
