Задачи на GROUP BY и HAVING
Группировка·junior

Сегментация фильмов по длине через CASE

Задача

Продуктовая команда хочет понять структуру каталога по длительности: «Разбей фильмы на три корзины — короткие (меньше 90 минут), средние (90–120) и длинные (больше 120) — и посчитай, сколько фильмов в каждой».

Верни название сегмента и число фильмов в нём.

Схема данных

Учебная база проката dvdrental, одна таблица:

  • film(film_id, title, length, ...) — каталог; length — длительность в минутах (integer).

Решение

SELECT
  CASE
    WHEN length < 90 THEN 'короткие (<90)'
    WHEN length <= 120 THEN 'средние (90–120)'
    ELSE 'длинные (>120)'
  END AS segment,
  count(*) AS films
FROM film
GROUP BY segment
ORDER BY films DESC;

Разбор

Фокус задачи — сгруппировать не по готовой колонке, а по вычисленному признаку. В базе нет поля «сегмент по длине», поэтому мы конструируем его на лету через CASE.

CASE работает как лесенка условий сверху вниз: проверяет WHEN по порядку и возвращает значение первого сработавшего. Порядок веток тут критичен. Для фильма на 100 минут первое условие length < 90 ложно, второе length <= 120 истинно — он попадает в «средние». А теперь тонкость: во второй ветке я пишу просто length <= 120, без нижней границы >= 90. Это не ошибка и не лень — до второй ветки доходят только фильмы, которые НЕ прошли первую, то есть уже гарантированно >= 90. CASE отсекает их раньше. Если бы ветки шли в обратном порядке, логика сломалась бы. Это классическая ловушка: людям кажется, что каждую ветку надо ограничивать с двух сторон, но лесенка CASE уже сделала половину работы.

Дальше GROUP BY segment группирует строки по результату CASE. PostgreSQL разрешает ссылаться в GROUP BY на алиас выражения из SELECT, поэтому пишем коротко GROUP BY segment вместо повтора всего CASE. В более строгих СУБД пришлось бы дублировать выражение целиком — стоит это знать, если код поедет на другую базу.

COUNT(*) считает фильмы в каждой корзине, ORDER BY films DESC ставит самый населённый сегмент наверх. Три строки на выходе — по одной на корзину.

Если сегменты нужно не считать, а фильтровать по итогам (например, оставить только крупные группы), фильтр идёт в HAVING — как в задаче про крупные категории.

Ожидаемый результат

segment | films
--- | ---
длинные (>120) | 457
короткие (<90) | 320
средние (90–120) | 223

Прорешай такие задачи сам

Читать разбор полезно, а настоящая прокачка — самому писать запросы и получать обратную связь. В симуляторе живая база и проверка запросов, лёгкий режим — бесплатно.

Прорешать в бесплатной песочнице

Смежные задачи

Вопросы по теме