Отладка запросов и итоговый проект

Отладка 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.

Стратегия: три шага отладки. Когда запрос выполняется, но результат подозрительный, действуй последовательно.

Читай сообщение об ошибке — если оно есть, это первый и самый точный источник информации. Там указан тип и позиция проблемы.

  1. Упрощай по частям. Убери JOIN, WHERE, GROUP BY — оставь только SELECT ... FROM ... и проверь, работает ли базовая часть. Затем добавляй предложения по одному, пока проблема не проявится снова. Так ты изолируешь именно то место, которое ломает логику.

  2. Проверяй ожидаемое число строк. Если знаешь, сколько строк должно вернуться, сравни с фактическим: SELECT COUNT(*) FROM ... с тем же WHERE. Пустой результат сам по себе не доказывает ошибку: фильтр, диапазон или JOIN могут законно не найти строк. Сначала проверьте ожидаемый результат на известных данных, затем по отдельности WHERE и условия JOIN. Если условие сравнивает nullable-столбец с NULL, отдельно ищите = NULL и заменяйте его на IS NULL или IS NOT NULL.

Эти три шага работают в связке: синтаксические ошибки закрываются первым шагом, ошибки неоднозначности столбцов — тоже первым, а логические ошибки с NULL требуют второго и третьего, потому что СУБД на них не жалуется.