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

Ответ

Ключевое отличие заключается в моменте применения фильтрации в порядке выполнения SQL-запроса.

  • WHERE фильтрует строки до группировки (операция GROUP BY). Он работает с отдельными записями исходной таблицы.
  • HAVING фильтрует строки после группировки. Он работает с агрегированными результатами (группами), созданными GROUP BY.

Порядок выполнения SQL-запроса (упрощенно)

  1. FROM / JOIN (определение таблиц)
  2. WHERE (фильтрация строк на этом этапе)
  3. GROUP BY (группировка отфильтрованных строк)
  4. HAVING (фильтрация сгруппированных результатов)
  5. SELECT (выбор полей)
  6. ORDER BY (сортировка)

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

Пример 1: WHERE (фильтрация до группировки)

"Найти среднюю зарплату по отделам, но только для сотрудников, работающих в компании больше года."

SELECT DepartmentId, AVG(Salary) as AvgSalary
FROM Employees
WHERE DATEDIFF(year, HireDate, GETDATE()) > 1 -- Фильтр применяется к КАЖДОМУ сотруднику
GROUP BY DepartmentId;

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

Пример 2: HAVING (фильтрация после группировки)

"Найти отделы, в которых средняя зарплата превышает 75000."

SELECT DepartmentId, AVG(Salary) as AvgSalary
FROM Employees
GROUP BY DepartmentId
HAVING AVG(Salary) > 75000; -- Фильтр применяется к РЕЗУЛЬТАТУ агрегации (к группам)

Здесь сначала вычисляется средняя зарплата для каждого отдела, а затем HAVING отбрасывает те группы (отделы), где это среднее значение не превышает 75000.

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

"Найти отделы, где средняя зарплата действующих сотрудников превышает 80000."

SELECT DepartmentId, AVG(Salary) as AvgSalary
FROM Employees
WHERE IsActive = 1 -- Сначала берем только активных сотрудников
GROUP BY DepartmentId
HAVING AVG(Salary) > 80000; -- Затем фильтруем результаты агрегации

Главное правило

  • Используйте WHERE для условий, основанных на данных отдельных строк (например, Salary > 50000, Name LIKE 'A%').
  • Используйте HAVING для условий, основанных на результатах агрегатных функций (SUM, AVG, COUNT, MIN, MAX) после группировки.

Ответ 18+ 🔞

Давай разжую эту тему про WHERE и HAVING, а то народ путается, как последние идиоты. Ситуация, в общем-то, проще пареной репы, если понять одну простую вещь: когда эта хуйня срабатывает.

Представь, что ты начальник цеха, а данные в таблице — это твои работяги.

Суть, блядь, вот в чём:

  • WHERE — это ты стоишь на входе в проходную и отсеиваешь мудаков ДО того, как они зашли в цех и начали работать. "Ты — пьяный, нахуй иди. Ты — без пропуска, тоже нахуй".
  • HAVING — это ты уже ПОСЛЕ рабочего дня смотришь на итоговые показатели по бригадам и решаешь: "Ага, бригада Иванова сделала меньше 100 деталей — вся бригада нахуй, премии не будет".

Как SQL-запрос выполняется (грубо говоря):

  1. FROM — привезли всех работяг со всех участков в одно место. Толпа, срака, кишмя кишит.
  2. WHERE — твой вышибала на проходной начинает чистку. "Больше года не работаешь? Нахуй отсюда!" Отсеял кучу народа.
  3. GROUP BY — оставшихся трезвых и годных рассадили по бригадам (отделам).
  4. HAVING — теперь ты смотришь на сводку по каждой бригаде. "Средняя зарплата в бригаде меньше 75к? Всю бригаду нахуй из отчёта!"
  5. SELECT — выбираешь, что именно показывать в итоговой бумажке (номер бригады и их среднюю зарплату).
  6. ORDER BY — сортируешь эти бумажки как тебе удобно.

Примеры, чтобы въехать окончательно:

Пример 1: WHERE (отсев на входе)

"Дайте мне среднюю зарплату по отделам, но только по тем, кто уже не новичок, работает больше года."

SELECT DepartmentId, AVG(Salary) as AvgSalary
FROM Employees
WHERE DATEDIFF(year, HireDate, GETDATE()) > 1 -- Стой на проходной! Меньше года стажа? Нахуй иди, в статистику не попадёшь!
GROUP BY DepartmentId;

WHERE тут — это фильтр по каждой отдельной строке (по каждому работяге). Сначала выкинем всех зеленых, потом оставшихся сгруппируем.

Пример 2: HAVING (отсев по итогам)

"Найти отделы, где средняя зарплата зашкаливает за 75 тысяч."

SELECT DepartmentId, AVG(Salary) as AvgSalary
FROM Employees
GROUP BY DepartmentId
HAVING AVG(Salary) > 75000; -- Всё, бригады собраны. Теперь смотрим: твоя средняя зарплата 74к? Мало, нахуй такую бригаду из отчёта.

Вот тут уже поздно на входе стоять. Мы сначала всех сгруппировали, посчитали среднюю по каждой группе, а потом HAVING отфильтровал те группы, где результат нас не устраивает. Без группировки HAVING — нихуя не работает.

Пример 3: Вместе, блядь, как умные люди

"Найти отделы, где средняя зарплата активных сотрудников больше 80к."

SELECT DepartmentId, AVG(Salary) as AvgSalary
FROM Employees
WHERE IsActive = 1 -- Шаг 1: Вышибала. Ты уволен или в отпуске? Нахуй с глаз долой, нас интересуют только работающие прямо сейчас.
GROUP BY DepartmentId
HAVING AVG(Salary) > 80000; -- Шаг 2: Из оставшихся собрали бригады. Средняя по бригаде меньше 80к? Бригада — лохи, в финальный отчёт не идёте.

Идеально. Сначала отсекли балласт на уровне строк, потом сгруппировали то, что осталось, и потом отфильтровали уже сгруппированные результаты.

Итоговое правило, чтобы не ебать мозг:

  • WHERE — это про ПОЛЯ ИЗ ТАБЛИЦЫ (Salary, HireDate, Name). "Где зарплата > 50000". Фильтруем строки ДО группировки.
  • HAVING — это почти всегда про РЕЗУЛЬТАТЫ АГРЕГАТОВ (AVG(Salary), COUNT(*), SUM(Revenue)). "Где средняя зарплата > 50000". Фильтруем группы ПОСЛЕ того, как их создали.

Всё. Если после этого всё ещё путаешь — иди нахуй, иди в менеджеры.