В SQL иногда путают
WHERE и HAVING, потому что внешне они решают похожую задачу — отфильтровать результат. На практике это два разных этапа выполнения запроса с разной семантикой.Представим таблицу заказов:
orders(id, customer_id, amount)
Нужно выбрать заказы дороже 100.
Корректный и очевидный вариант:
SELECT *
FROM orders
WHERE amount > 100;
WHERE применяется до агрегации и фильтрует отдельные строки исходной таблицы.Теперь другая задача: найти клиентов, у которых сумма всех заказов больше 1000.
Интуитивная, но неверная попытка:
SELECT customer_id, SUM(amount) AS total_amount
FROM orders
WHERE SUM(amount) > 1000
GROUP BY customer_id;
Этот запрос некорректен: агрегатные функции не могут использоваться в
WHERE, потому что на момент применения WHERE агрегатов ещё не существует.Правильный вариант —
HAVING:SELECT customer_id, SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id
HAVING SUM(amount) > 1000;
HAVING применяется после GROUP BY и фильтрует уже сформированные группы.Важно понимать разницу по этапам:
WHERE — фильтрует строки до группировки; GROUP BY — формирует группы; HAVING — фильтрует группы; SELECT — формирует итоговый результат.Частая оптимизационная ошибка — переносить условия из
WHERE в HAVING без необходимости:SELECT customer_id, SUM(amount)
FROM orders
GROUP BY customer_id
HAVING amount > 100;
Такой запрос либо не выполнится, либо будет логически неверным:
amount — это поле строки, а HAVING работает с группой.Корректный и оптимальный вариант — комбинировать:
SELECT customer_id, SUM(amount) AS total_amount
FROM orders
WHERE amount > 100
GROUP BY customer_id
HAVING SUM(amount) > 1000;
Здесь:
WHERE отсекает мелкие заказы до агрегации (меньше данных); HAVING проверяет условие на уровне группы.🔥 Используй
WHERE для фильтрации строк и HAVING — только для условий на агрегаты и группы. Это влияет не только на корректность, но и на производительность запроса➡️ SQL Ready | #практика