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

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

1.3 Junior🔥 61 комментариев
#SQL и базы данных

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

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

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

Различия между WHERE и HAVING в SQL

WHERE и HAVING — это два различных механизма фильтрации в SQL, которые работают на разных этапах обработки запроса. Понимание их различий критично для написания эффективных запросов и получения правильных результатов.

Концептуальные различия

WHERE — фильтрация строк ДО агрегации

WHERE применяется к индивидуальным строкам таблицы ДО группировки (GROUP BY) и агрегирующих функций. Это условие работает с исходными данными.

SELECT department_id, COUNT(*) as emp_count
FROM employees
WHERE salary > 50000  -- Фильтруем строки ДО GROUP BY
GROUP BY department_id;

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

  1. Сначала из таблицы employees выбираются только строки, где salary > 50000
  2. Потом результаты группируются по department_id
  3. Затем считается количество сотрудников в каждом отделе

HAVING — фильтрация ПОСЛЕ агрегации

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

SELECT department_id, COUNT(*) as emp_count
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 5;  -- Фильтруем группы ПОСЛЕ GROUP BY

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

  1. Все сотрудники группируются по department_id
  2. Для каждой группы считается количество
  3. Выбираются только те группы, где count > 5

Сравнительная таблица

КритерийWHEREHAVING
Применяется кИндивидуальным строкамГруппам строк
Когда работаетДО GROUP BY (ДО агрегации)ПОСЛЕ GROUP BY (ПОСЛЕ агрегации)
Может использоватьСтолбцы таблицыАгрегирующие функции (SUM, COUNT, AVG и т.д.)
ПроизводительностьБолее эффективен (меньше данных обрабатывается)Менее эффективен (обрабатывает все данные)
Синтаксис в запросеПеред GROUP BYПосле GROUP BY
Может фильтровать по неагрегированным столбцамДаЗависит от СУБД

Практические примеры

Пример 1: Базовое сравнение

-- Вариант 1: WHERE — сначала фильтруем по условию на строки
SELECT 
    department_id,
    AVG(salary) as avg_salary,
    COUNT(*) as emp_count
FROM employees
WHERE hire_date >= '2020-01-01'  -- Только сотрудники, нанятые после 2020
GROUP BY department_id;

-- Вариант 2: HAVING — фильтруем уже подсчитанные группы
SELECT 
    department_id,
    AVG(salary) as avg_salary,
    COUNT(*) as emp_count
FROM employees
GROUP BY department_id
HAVING AVG(salary) > 60000;  -- Только отделы со средней зарплатой выше 60000

Пример 2: Комбинирование WHERE и HAVING

SELECT 
    department_id,
    position,
    AVG(salary) as avg_salary,
    COUNT(*) as emp_count
FROM employees
WHERE years_of_experience >= 3  -- WHERE: опыт не менее 3 лет
GROUP BY department_id, position
HAVING COUNT(*) >= 2 AND AVG(salary) > 55000;  -- HAVING: группы с 2+ людьми и зарплатой > 55000

Обработка этого запроса:

  1. Фильтр WHERE отсекает всех сотрудников с опытом < 3 лет
  2. Оставшихся сотрудников группируют по department_id и position
  3. Фильтр HAVING оставляет только группы с count >= 2 и avg_salary > 55000

Пример 3: Сложные агрегирующие условия

SELECT 
    year,
    month,
    SUM(sales) as total_sales,
    COUNT(DISTINCT customer_id) as unique_customers,
    AVG(order_amount) as avg_order
FROM orders
WHERE status = 'completed'  -- Только завершённые заказы
    AND order_date >= '2023-01-01'  -- За последние 2 года
GROUP BY year, month
HAVING SUM(sales) > 100000  -- Месяцы с продажами > 100000
    AND COUNT(DISTINCT customer_id) > 50  -- Более 50 уникальных клиентов
    AND AVG(order_amount) > 500  -- Средний заказ > 500
ORDER BY year DESC, month DESC;

Пример 4: Использование агрегирующих функций

-- ОШИБКА: WHERE не может использовать COUNT
SELECT department_id, COUNT(*) as emp_count
FROM employees
WHERE COUNT(*) > 5  -- ОШИБКА: COUNT нельзя использовать в WHERE
GROUP BY department_id;

-- ПРАВИЛЬНО: используем HAVING для агрегирующих функций
SELECT department_id, COUNT(*) as emp_count
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 5;  -- Правильно

Пример 5: Оптимизация с WHERE для производительности

-- НЕОПТИМАЛЬНО: HAVING фильтрует после обработки всех 1М строк
SELECT 
    customer_id,
    SUM(order_amount) as total_spent
FROM orders
GROUP BY customer_id
HAVING customer_id NOT IN (100, 200, 300);  -- Лучше в WHERE

-- ОПТИМАЛЬНО: WHERE фильтрует сразу, обрабатывается меньше строк
SELECT 
    customer_id,
    SUM(order_amount) as total_spent
FROM orders
WHERE customer_id NOT IN (100, 200, 300)
GROUP BY customer_id;

Правила использования

Используй WHERE когда:

  1. Фильтруешь по значениям в столбцах таблицы
  2. Используешь операторы сравнения (=, >, <, IN, BETWEEN, LIKE)
  3. Хочешь улучшить производительность (меньше данных для обработки)
  4. Условие применяется к отдельным строкам

Используй HAVING когда:

  1. Фильтруешь по результатам агрегирующих функций (COUNT, SUM, AVG, MIN, MAX)
  2. Условие применяется к группам данных
  3. Нужно отсеять группы по агрегированным значениям
  4. Комбинируешь несколько агрегирующих функций в условии

Порядок обработки в SQL-запросе

1. FROM           — выбор таблицы
2. WHERE          — фильтрация строк
3. GROUP BY       — группировка
4. HAVING         — фильтрация групп
5. SELECT         — выбор столбцов
6. ORDER BY       — сортировка
7. LIMIT/OFFSET   — ограничение результатов

Важно помнить: WHERE работает на этапе 2, а HAVING на этапе 4. Это определяет, какие данные будут обработаны и как эффективно выполнится запрос.