Практика: типичные ошибки в условиях

Практика: типичные ошибки в условиях

Этот урок завершает модуль про фильтрацию и сортировку. Вы уже освоили WHERE, логические операторы AND/OR/NOT, ORDER BY, LIMIT/OFFSET и приоритет операторов. Теперь разберём самые частые ошибки, которые делают новички при написании условий WHERE. Умение находить и исправлять такие ошибки — важный навык, который отличает уверенного SQL-разработчика от начинающего.

Ошибка 1: сравнение с NULL через «=»

Пожалуй, самая распространённая ловушка в SQL. Попытка найти строки, где колонка пустая:

-- Неправильно: никогда не вернёт строки
SELECT * FROM customers WHERE phone = NULL;

-- Правильно
SELECT * FROM customers WHERE phone IS NULL;

Почему = NULL не работает? В SQL NULL означает «неизвестное значение». Сравнение «неизвестное = неизвестное» даёт не TRUE и не FALSE, а опять NULL. А строки, где условие WHERE даёт NULL, фильтруются — они не попадают в результат.

Единственные операторы для проверки на NULL: IS NULL и IS NOT NULL.

-- Правильно: найти клиентов без email
SELECT name FROM customers WHERE email IS NULL;

-- Правильно: найти клиентов с email
SELECT name FROM customers WHERE email IS NOT NULL;

Проверь себя: что вернёт WHERE column = NULL для строки, где column IS NULL?

Ошибка 2: регистр строк

PostgreSQL чувствителен к регистру строковых значений. Если данные записаны как 'Москва', а вы ищете 'москва' — результата не будет:

-- Данные в таблице: 'Москва'

SELECT * FROM customers WHERE city = 'москва';     -- 0 строк
SELECT * FROM customers WHERE city = 'МОСКВА';    -- 0 строк
SELECT * FROM customers WHERE city = 'Москва';    -- нашли!

Если регистр данных в базе непредсказуем (кто-то написал «москва», кто-то «Москва», кто-то «МОСКВА»), используйте функцию LOWER() для приведения к единому регистру перед сравнением:

SELECT * FROM customers WHERE LOWER(city) = 'москва';

Это вернёт строки независимо от того, как записан город. Обратная сторона: LOWER(city) вычисляется для каждой строки, что может быть медленнее. На больших таблицах для таких запросов создают специальные индексы.

Ошибка 3: одинарные и двойные кавычки

В PostgreSQL одинарные и двойные кавычки — разные вещи:

-- Правильно: строковый литерал в одинарных кавычках
SELECT * FROM products WHERE name = 'Ноутбук';

-- Ошибка в PostgreSQL: двойные кавычки — для имён объектов
SELECT * FROM products WHERE name = "Ноутбук";
-- ERROR: column "Ноутбук" does not exist

PostgreSQL интерпретирует двойные кавычки как имя колонки, а не как строку. Результат: «колонки с таким именем не существует».

Строковые значения — только в одинарных кавычках.

Ошибка 4: использование псевдонима в WHERE

Напомним ошибку из урока про WHERE:

-- Неправильно
SELECT price * 1.2 AS price_vat
FROM   products
WHERE  price_vat > 5000;   -- ERROR: column "price_vat" does not exist

-- Правильно
SELECT price * 1.2 AS price_vat
FROM   products
WHERE  price * 1.2 > 5000;

WHERE выполняется до SELECT, поэтому псевдонимы из SELECT-списка ещё не существуют в момент применения WHERE. Нужно повторить выражение.

Ошибка 5: потеря условия из-за приоритета AND/OR

Классическая ошибка приоритета, которую мы подробно разбирали:

-- Запрос с ошибкой: ищем "активных из Москвы или активных из Питера"
-- Но получаем "всех из Москвы + активных из Питера"
SELECT * FROM customers
WHERE city = 'Москва' OR city = 'Санкт-Петербург' AND status = 'active';

-- Правильный запрос
SELECT * FROM customers
WHERE (city = 'Москва' OR city = 'Санкт-Петербург') AND status = 'active';

Признак этой ошибки: запрос возвращает «лишние» строки, которые не должны были попасть в результат.

Ошибка 6: лишний DISTINCT там, где он не нужен

Иногда DISTINCT добавляют «на всякий случай», хотя дубликатов нет:

-- Если id — первичный ключ, DISTINCT ничего не делает, но тормозит
SELECT DISTINCT id, name FROM products ORDER BY id;

-- Правильно: просто без DISTINCT
SELECT id, name FROM products ORDER BY id;

DISTINCT вынуждает СУБД сравнивать все строки между собой. Если уникальность и так гарантирована (например, запрос по первичному ключу), DISTINCT — лишняя нагрузка.

Ошибка 7: LIMIT без ORDER BY

Получить «первые 10 товаров» без сортировки:

-- Результат непредсказуем
SELECT name, price FROM products LIMIT 10;

-- Предсказуемый результат: 10 дешевейших товаров
SELECT name, price FROM products ORDER BY price ASC LIMIT 10;

Без ORDER BY СУБД возвращает строки в произвольном порядке — каком именно, зависит от внутреннего хранения данных и может меняться от запуска к запуску.

Ошибка 8: неверный знак сравнения

Путаница между «включительно» и «исключительно»:

-- Хотели пользователей от 18 лет включительно
-- Написали строго больше — потеряли 18-летних
SELECT * FROM users WHERE age > 18;   -- 19, 20, 21...

-- Правильно: от 18 и старше
SELECT * FROM users WHERE age >= 18;  -- 18, 19, 20...

Аналогично с верхней границей: < 30 исключает 30-летних, <= 30 включает.

Особенно часто ошибка встречается при работе с датами:

-- Хотели все заказы за 2024 год
-- Написали < '2025-01-01' — правильно, но можно написать понятнее
SELECT * FROM orders WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01';

-- Альтернатива: EXTRACT или date_trunc (изучим позже)

Ошибка 9: забытые строки из-за NULL в логических операциях

Тонкая ошибка: колонка может содержать NULL, и это «отравляет» результат логических операций.

-- Хотим всех сотрудников с зарплатой не равной 100000
SELECT name FROM employees WHERE salary <> 100000;

Казалось бы, всё просто. Но строки, где salary IS NULL, в результат не попадутNULL <> 100000 даёт NULL, а не TRUE.

Если нужно включить и строки с NULL:

SELECT name FROM employees WHERE salary <> 100000 OR salary IS NULL;

Ошибка 10: опечатка в имени таблицы или колонки

Банальная, но частая ошибка:

SELECT emplyee_name FROM employes;
-- ERROR: relation "employes" does not exist

PostgreSQL не делает «умных» предположений. «Нет такой таблицы» — значит нет. Проверьте написание через \dt (в psql) или воспользуйтесь автодополнением в GUI-клиенте.

Подход к отладке: делите и властвуйте

Когда запрос возвращает не то, что ожидалось, полезна стратегия «разбить на части»:

  1. Запустите запрос без WHERE — убедитесь, что данные в таблице вообще есть
  2. Добавляйте условия WHERE по одному — находите, при каком условии «теряются» нужные строки
  3. Проверьте значения в базе: SELECT DISTINCT city FROM customers покажет реальный список городов
  4. Проверьте NULL: SELECT * FROM customers WHERE phone IS NULL — есть ли пустые телефоны?

Такой подход позволяет быстро найти ошибку даже в сложном условии из 5–6 частей.

Ещё один приём — вынести сложное условие в простые части и проверить каждую:

-- Оригинальный запрос с подозрением на ошибку
SELECT * FROM orders
WHERE status = 'new' OR status = 'pending' AND total > 1000;

-- Шаг 1: проверить сколько строк при только первом условии
SELECT count(*) FROM orders WHERE status = 'new';

-- Шаг 2: проверить сколько строк при только втором условии
SELECT count(*) FROM orders WHERE status = 'pending' AND total > 1000;

-- Шаг 3: сравнить сумму с результатом оригинала — если не совпадает, значит логика неверна
SELECT count(*) FROM orders WHERE status = 'new' OR status = 'pending' AND total > 1000;

Если сумма count из шагов 1 и 2 не совпадает с итогом из шага 3 — в условии есть пересечение или ошибка приоритета.

Краткий итог

  • = NULL не работает — используйте IS NULL и IS NOT NULL
  • PostgreSQL чувствителен к регистру строк; LOWER() помогает при непредсказуемых данных
  • Строки — в одинарных кавычках; двойные — для имён объектов
  • Псевдонимы SELECT недоступны в WHERE — повторяйте выражение
  • Приоритет AND > OR — при смешивании всегда используйте скобки
  • NULL в <> условии не возвращает TRUE — добавляйте явную проверку OR IS NULL
  • При отладке: убирайте условия по одному, проверяйте реальные значения в базе

Что дальше

Вы завершили модуль 3. Теперь вы умеете фильтровать, сортировать, ограничивать результат и правильно выстраивать логику условий. В следующем модуле — специализированные операторы: LIKE для поиска по шаблону, IN для списков значений, BETWEEN для диапазонов, IS NULL, и мощный CASE WHEN для условных выражений.

Попробуйте интерактивную версию

Практические задачи, квизы и AI-наставник — бесплатный старт без карты

Перейти к практике