Сегментация фильмов по длине через 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
Прорешай такие задачи сам
Читать разбор полезно, а настоящая прокачка — самому писать запросы и получать обратную связь. В симуляторе живая база и проверка запросов, лёгкий режим — бесплатно.
Прорешать в бесплатной песочнице