УРОК 9 / 27· ≈ 25 мин

Фильтрация групп: HAVING

WHERE и HAVING — два разных фильтра

Мы умеем фильтровать строки (WHERE) и считать итоги по группам (GROUP BY). А как отфильтровать сами группы — например, «оставить только страны, где не меньше 100 аэропортов»? Тут WHERE не подойдёт: он работает до группировки и не знает про COUNT(*). Для фильтрации групп есть отдельный раздел — HAVING:

SELECT country, COUNT(*) AS cnt
FROM airports
GROUP BY country
HAVING COUNT(*) >= 100
ORDER BY cnt DESC, country;

Разница в одной фразе:

  • WHERE — фильтрует строки до группировки (не может использовать агрегаты);
  • HAVING — фильтрует группы после агрегации (в нём как раз используют COUNT, SUM и т.п.).

Полный порядок выполнения

Теперь у нас собрался почти весь запрос. База вычисляет его в таком порядке:

FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
Логический порядок выполнения SELECT: FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY, LIMIT

Поэтому WHERE отсеивает строки до группировки, а HAVING — группы после. Часто их используют вместе: сначала WHERE сужает строки, потом GROUP BY группирует, потом HAVING отбрасывает мелкие/ненужные группы.

Типичные ошибки

  • Псевдоним в HAVING. HAVING cnt >= 100 в PostgreSQL не сработает: HAVING выполняется раньше SELECT, где появляется псевдоним. Повторите выражение: HAVING COUNT(*) >= 100. А вот в ORDER BY псевдоним уже доступен.
  • Обычное условие в HAVING. HAVING country = 'Japan' сработает, но такое условие честнее и обычно эффективнее писать в WHERE: строки отсеются ещё до группировки.
  • HAVING без GROUP BY. Тогда вся таблица считается одной группой, и условие проверяется один раз — запрос вернёт либо одну строку, либо ничего.
💡 Практическое правило: условие по исходным строкам → в WHERE; условие по результату агрегата (COUNT(*) > 5 и т.п.) → в HAVING. Неагрегированное условие иногда можно записать и в HAVING, но WHERE яснее и обычно позволяет раньше сократить объём данных.

Практика

7
  1. Тест 1 — Куда поставить условие «COUNT(*) >= 100»?
  2. Тест 2 — Почему в PostgreSQL не сработает «HAVING cnt >= 100», где cnt — псевдоним из SELECT?
  3. Задача 1 — Страны со 100+ аэропортами
  4. Задача 2 — Вместительные самолёты (200+ мест)
  5. Задача 3 — Страны с 50–100 аэропортами
  6. Задача 4 — Бронирования на несколько пассажиров
  7. Задача 5 — WHERE + GROUP BY + HAVING вместе

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

Зарегистрироваться и решитьВойти

Потренируйтесь в тренажёре

4

Задачи на ту же тему, но на другой базе — продажи магазина электроники. Хороший способ проверить, что тема понятна, а не просто запомнилась на примерах урока.

Агрегатные функции и GROUP BYСледующий урок: CASE: условия внутри запроса