JavaRush /Курсы /SQL SELF /Сравнение WHERE и HAVING: разбор порядка выполнения и при...

Сравнение WHERE и HAVING: разбор порядка выполнения и примеры

SQL SELF
8 уровень , 2 лекция
Открыта

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

Так чем же WHERE отличается от HAVING, когда использовать один, а когда другой, и как они взаимосвязаны? Это поможет вам не запутаться в логике запросов и эффективно фильтровать данные. Давайте обобщим наши знания про WHERE и HAVING.

Что такое WHERE?

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

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

Пример:

SELECT *
FROM students
WHERE age > 18;

Этот запрос выберет всех студентов старше 18 лет до выполнения любых других операций.

Что такое HAVING?

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

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

Пример:

SELECT корзина, COUNT(*)
FROM яблоки
GROUP BY корзина
HAVING COUNT(*) > 10;

Этот запрос выберет только те корзины, где количество яблок больше 10.

Основные различия:

Особенность WHERE HAVING
Применение Фильтрует строки до группировки Фильтрует группы после группировки
Работа с агрегацией Нельзя использовать агрегатные функции Можно использовать агрегатные функции
Цель Убирает лишние строки для группировки Убирает группы, которые не удовлетворяют условию

Порядок выполнения WHERE, GROUP BY и HAVING

Чтобы лучше понять, как работают WHERE и HAVING, давайте посмотрим на порядок выполнения SQL-запросов:

  1. Сначала выполняется FROM, выбираются строки из таблицы.
  2. Затем применяется WHERE, фильтруются только те строки, которые соответствуют условиям.
  3. После этого выполняется группировка с помощью GROUP BY. Мы получаем новую таблицу с данными групп.
  4. Применяется HAVING, фильтруются группы, которые соответствуют условиям.
  5. Наконец, выбираются результаты SELECT.

Схематично это выглядит так:

1. FROM → 2. WHERE → 3. GROUP BY → 4. HAVING → 5. SELECT

Пример:

SELECT department, AVG(age) AS avg_age
FROM students
WHERE age > 18
GROUP BY department
HAVING AVG(age) > 20;

Здесь происходит следующее:

  1. В таблице students выбираются строки, где age > 18 (используется WHERE).
  2. Оставшиеся строки группируются по department.
  3. Для каждой группы рассчитывается средний возраст студентов.
  4. Группы, где средний возраст меньше или равен 20, исключаются HAVING.
  5. Результаты выводятся.

Примеры комбинированного использования

Пример 1: Фильтрация до и после группировки

Условие: найти факультеты, где больше 5 студентов, при этом учитываются только студенты старше 18 лет.

Исходная таблица students

id name department age gpa
1 Alex Lin ComputerSci 20 3.8
2 Maria Chi Math 22 3.5
3 Anna Song ComputerSci 19 4.0
4 Otto Art Math 17 3.9
5 Liam Park Physics 21 3.7
6 Jane Doe ComputerSci 23 3.6
7 Tom Brown Math 25 3.4
8 Sara White Math 19 3.8
9 John Smith ComputerSci 20 3.7
10 Emily Green Physics 18 3.9
11 Mark Blue ComputerSci 21 3.5
12 Zoe Black Math 22 3.6
13 Max Gray ComputerSci 20 3.9
14 Eva Gold Math 23 3.7
15 Nick Silver Physics 19 3.8

Запрос:

SELECT department, COUNT(*) AS student_count
FROM students
WHERE age > 18
GROUP BY department
HAVING COUNT(*) > 5;

Результат: -- Результат запроса

department student_count
ComputerSci 6

Пояснение:

  1. Сначала удаляем строки, где age <= 18 (условие WHERE).
  2. Группируем данные по факультетам (GROUP BY department).
  3. Вычисляем количество студентов в каждой группе.
  4. Убираем группы, где студентов меньше или равно 5 (HAVING COUNT(*) > 5).

Пример 2: Ошибка при использовании WHERE вместо HAVING

Условие: Найти факультеты, где средний возраст больше 22 лет.

Некорректный запрос:

SELECT department, AVG(age) AS avg_age
FROM students
WHERE AVG(age) > 22
GROUP BY department;

Ошибка: SQL не позволяет использовать агрегатные функции AVG в WHERE, так как на этом этапе агрегаты ещё не рассчитаны.

Правильный запрос:

SELECT department, AVG(age) AS avg_age
FROM students
GROUP BY department
HAVING AVG(age) > 22;

Здесь условие AVG(age) > 22 применяется после группировки.

Практические советы

Если вам нужно фильтровать строки, используйте WHERE. Пример: Найти всех сотрудников с зарплатой больше 5000.

SELECT *
FROM employees
WHERE salary > 5000;

Если вам нужно фильтровать группы, используйте HAVING. Пример: Найти отделы с общей зарплатой больше 100 000.

SELECT department, SUM(salary) AS total_salary
FROM employees
GROUP BY department
HAVING SUM(salary) > 100000;

Комбинируйте WHERE и HAVING для сложных условий.

Пример: Найти страны с количеством жителей больше 10 миллионов, учитывая только города, где население выше 1 миллиона.

SELECT country, SUM(population) AS total_population
FROM cities
WHERE population > 1000000
GROUP BY country
HAVING SUM(population) > 10000000;

Типичные ошибки и пути их решения

Одна из самых распространённых ошибок — это путаница между WHERE и HAVING. Например, попытка использовать агрегатную функцию в WHERE:

SELECT department, COUNT(*)
FROM students
WHERE COUNT(*) > 10
GROUP BY department;

Такой запрос выдаст ошибку, так как агрегатные расчёты недоступны на этапе выполнения WHERE. Правильный подход — использовать HAVING:

SELECT department, COUNT(*)
FROM students
GROUP BY department
HAVING COUNT(*) > 10;

Ещё одна ошибка связана с выбором неправильных условий для WHERE. Например:

SELECT department, AVG(age) AS avg_age
FROM students
WHERE avg_age > 20
GROUP BY department;

Здесь условие avg_age > 20 некорректно, так как avg_age ещё не рассчитан. Решение — переместить это условие в HAVING:

SELECT department, AVG(age) AS avg_age
FROM students
GROUP BY department
HAVING AVG(age) > 20;

Надеюсь,теперь у вас есть чёткое понимание, чем отличаются WHERE и HAVING, как их правильно использовать и как избежать типичных ошибок. Эти знания пригодятся вам при создании сложных отчётов, фильтрации данных для анализа и оптимизации запросов. Т.е. для большей половины реальных SQL-запросов, которые вы будете писать :)

2
Задача
SQL SELF, 8 уровень, 2 лекция
Недоступна
Найти факультеты с числом студентов старше 18 больше 5
Найти факультеты с числом студентов старше 18 больше 5
2
Задача
SQL SELF, 8 уровень, 2 лекция
Недоступна
Найти факультеты с максимальным возрастом студентов выше 23 лет
Найти факультеты с максимальным возрастом студентов выше 23 лет
Комментарии (7)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Dmitry Ivanchenko Уровень 15
13 января 2026
JavaRush двигается по пути Duolingo. Это как минимум на 2/3 ИИ сгенерированная статья с палевными 👉
Slevin Уровень 11
2 сентября 2025
Порядок выполнения WHERE, GROUP BY и HAVING Полезно было бы указать, что на шаге 3.5 - Вычисляются агрегатные функции
Ra Уровень 35 Student
23 августа 2025
Есть ещё такая конструкция

SELECT classroom
FROM Schedule
GROUP BY classroom
ORDER BY count(*) DESC
FETCH FIRST 1 ROW WITH TIES -- !!!
Надо получить, какие кабинеты в расписании наиболее загружены. 📌 FETCH FIRST N ROW (POSTGRES 13+) Означает "вернуть N строк" из отсортированного результата Аналог LIMIT N в MySQL/PostgreSQL или TOP N в SQL Server 🤝 WITH TIES Ключевая особенность: возвращает не только первую строку, но и все последующие строки, которые имеют одинаковые значения в столбцах, указанных в ORDER BY Работает только в сочетании с ORDER BY Если несколько строк имеют одинаковые значения в сортировке, все они будут возвращены.
Anemon Уровень 13 Expert
17 августа 2025
🤓
Denis Murashko Уровень 27
4 августа 2025
при запуске приходит ответ,а при проверке он не подходит HAVING max_age > 23
Anemon Уровень 13 Expert
17 августа 2025
Если это правда, то это ошибка валидатора. В реальной БД так не получится, т.к. SELECT выполняется последним.
Anton Nikonorov Уровень 9
22 августа 2025
На WebStorm в консоль вылезает ошибка, если использовать алиас из SELECT в HAVING, например:

SELECT
    department,
    COUNT(*) AS student_count
FROM
    students
WHERE age > 18
GROUP BY department
HAVING student_count > 5;
Ошибка валидатора:

Unable to resolve column 'student_count'
Замена 'student_count' на COUNT(*) моментально эту проблему решает.