WHERE

WHERE фильтрует строки до группировки. В результат проходят только строки, для которых условие вычислилось в TRUE.

SELECT id, user_id, total
FROM orders
WHERE state = 'PAID'
  AND total >= 1000.00;

Трехзначная логика

В SQL есть TRUE, FALSE и UNKNOWN. Любое обычное сравнение с NULL дает UNKNOWN.

SELECT id
FROM users
WHERE status IS NULL;

Ловушка:

-- Если подзапрос вернет хотя бы один NULL,
-- результат может оказаться пустым.
WHERE id NOT IN (SELECT user_id FROM blocked_users)

Надежный вариант:

WHERE NOT EXISTS (
    SELECT 1
    FROM blocked_users AS b
    WHERE b.user_id = users.id
)

Условия, удобные для индекса

Выражение называют sargable, если СУБД может превратить его в диапазон поиска по индексу.

-- Индекс по created_at можно использовать как диапазон.
WHERE created_at >= TIMESTAMP '2026-07-01 00:00:00'
  AND created_at <  TIMESTAMP '2026-08-01 00:00:00'

Менее удачный вариант:

WHERE EXTRACT(YEAR FROM created_at) = 2026

Функция над столбцом часто мешает обычному индексу. Возможные решения: переписать условие диапазоном или создать функциональный индекс, если СУБД его поддерживает.

Приоритет операторов

AND обычно имеет более высокий приоритет, чем OR, но важное условие лучше выражать скобками:

WHERE state = 'PAID'
  AND (total >= 1000 OR user_id = 7)

Ловушки

  • WHERE total <> 0 не включает строки с NULL.
  • Не добавляй OR column IS NULL автоматически: это меняет бизнес-смысл и план.
  • Параметры должны передаваться через prepared statement; конкатенация пользовательского ввода создает SQL injection.
  • Фильтр по правой таблице в WHERE может превратить LEFT JOIN в фактический INNER JOIN.

Связано: Операторы IS NULL BETWEEN IN, Оператор LIKE, Индексы SQL, Запрос из 2х таблиц.

Вопросы

Когда выполняется WHERE относительно GROUP BY? Логически до группировки.

Почему column = NULL не работает? Сравнение дает UNKNOWN; нужен IS NULL.

Чем опасна функция над индексированным столбцом? Она может сделать обычный индекс неприменимым для поиска.

Как безопасно подставлять значения? Через параметры prepared statement, а не склейку SQL-строки.