← Назад к вопросам

В чём разница между WHERE и HAVING?

1.7 Middle🔥 141 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между WHERE и HAVING в SQL

Ключевое различие между операторами WHERE и HAVING заключается в времени их применения в процессе выполнения запроса и в типах данных, которые они могут фильтровать. Оба служат для ограничения результирующего набора данных, но используются в принципиально разных контекстах.

Основные отличия

КритерийWHEREHAVING
Этап выполненияФильтрация строк до группировки (GROUP BY).Фильтрация после группировки (GROUP BY).
Объект фильтрацииРаботает с отдельными записями (строками) таблицы.Работает с агрегированными группами данных.
Использование агрегатных функцийНе может напрямую использовать агрегатные функции (SUM, AVG, COUNT и т.д.) в условии.Может и предназначен для использования агрегатных функций в условии.
Связь с GROUP BYМожет использоваться без предложения GROUP BY.Практически всегда используется вместе с предложением GROUP BY (кроме особых случаев в некоторых СУБД).

Подробное объяснение с примерами

1. WHERE: Фильтрация на уровне строк

Оператор WHERE применяется на самом раннем этапе обработки запроса — до каких-либо операций группировки, сортировки или агрегации. Его цель — отсеять ненужные строки из исходного набора данных.

-- Пример 1: Фильтрация отдельных заказов
SELECT OrderID, CustomerID, TotalAmount
FROM Orders
WHERE TotalAmount > 1000 AND OrderDate >= '2024-01-01';
-- Условие проверяется для КАЖДОЙ строки таблицы Orders

WHERE НЕ может использовать агрегатные функции:

-- НЕВЕРНО! Этот запрос вызовет ошибку.
SELECT CustomerID, SUM(TotalAmount)
FROM Orders
WHERE SUM(TotalAmount) > 5000 -- Агрегатная функция в WHERE запрещена!
GROUP BY CustomerID;

2. HAVING: Фильтрация на уровне групп

Оператор HAVING применяется после того, как данные сгруппированы с помощью GROUP BY. Он фильтрует не исходные строки, а уже готовые группы, созданные в результате группировки. Поэтому он имеет прямой доступ к результатам агрегатных функций.

-- Пример 2: Фильтрация групп клиентов по общей сумме заказов
SELECT CustomerID, COUNT(OrderID) AS OrderCount, SUM(TotalAmount) AS TotalSpent
FROM Orders
GROUP BY CustomerID
HAVING SUM(TotalAmount) >359> 5000 AND COUNT(OrderID) >= 3;
-- Условие проверяется для КАЖДОЙ группы (сгруппированной по CustomerID)

В этом примере:

  • Сначала GROUP BY создаёт группы по каждому клиенту.
  • Для каждой группы вычисляется SUM(TotalAmount) и COUNT(OrderID).
  • Затем HAVING отбирает только те группы, где общая сумма (SUM) больше 5000 и количество заказов (COUNT) не меньше 3.

3. Совместное использование WHERE и HAVING

Часто их используют вместе в одном запросе для двухэтапной фильтрации: сначала отсеять ненужные строки, затем сгруппировать оставшиеся и отфильтровать ненужные группы.

-- Пример 3: Поиск VIP-клиентов 2024 года
SELECT CustomerID, COUNT(OrderID) AS OrderCount, SUM(TotalAmount) AS TotalSpent
FROM Orders
WHERE OrderDate >= '2024-01-01' -- 1. Берём только заказы за 2024 год
GROUP BY CustomerID
HAVING SUM(TotalAmount) > 10000 -- 2. Из сгруппированных клиентов выбираем тех, кто потратил больше 10к
ORDER BY TotalSpent DESC;

Логический порядок выполнения этого запроса:

  1. FROM Orders — выбирается таблица.
  2. WHERE OrderDate >= '2024-01 -01' — из неё удаляются все заказы, сделанные до 2024 года.
  3. GROUP BY CustomerID — оставшиеся заказы группируются по клиентам.
  4. HAVING SUM(TotalAmount) > 10000 — вычисляется сумма заказов для каждого клиента, и отбрасываются группы, где эта сумма меньше или равна 10000.
  5. SELECT — для прошедших фильтр групп выводятся указанные столбцы (включая результаты агрегации).
  6. ORDER BY — результаты сортируются.

Исключение и важный нюанс

В некоторых СУБД (например, MySQL, PostgreSQL) HAVING можно использовать без GROUP BY для фильтрации результатов агрегатных функций, применённых ко всей таблице как к одной группе. Однако это является скорее исключением, подтверждающим правило, и используется редко.

-- Пример 4: HAVING без GROUP BY (проверка агрегата по всей таблице)
SELECT SUM(TotalAmount) AS CompanyRevenue
FROM Orders
HAVING SUM(TotalAmount) > 1000000;

Резюме

  • Используйте WHERE, когда вам нужно отфильтровать исходные данные по значениям в столбцах (например, Status = 'Completed', Age > 18).
  • Используйте HAVING, когда вам нужно отфильтровать результаты группировки по условию, включающему агрегатные функции (например, AVG(Salary) > 50000, COUNT(*) < 5).

Правильное понимание этой разницы критически важно для написания эффективных и корректных SQL-

запросов, особенно в аналитических задачах и при построении сложных отчётов.