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

Аренды по дням недели

Задача

Управляющий планирует смены и хочет знать нагрузку по дням недели: «В какие дни у нас пик аренд? Посчитай число выдач по дням недели — от понедельника к воскресенью».

Верни день недели и число аренд в этот день.

Схема данных

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

  • rental(rental_id, rental_date, ...) — факты выдачи дисков; rental_date — момент выдачи (timestamp).

Решение

SELECT
  to_char(rental_date, 'Day') AS weekday,
  count(*) AS rentals
FROM rental
GROUP BY weekday, extract(isodow FROM rental_date)
ORDER BY extract(isodow FROM rental_date);

Разбор

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

to_char(rental_date, 'Day') возвращает название дня словом — Monday, Tuesday и так далее, — красиво для отчёта. Но по алфавиту эти слова выстроятся неправильно (Friday раньше Monday), поэтому сортировать по названию нельзя. Здесь выручает extract(isodow FROM rental_date) — он даёт номер дня по ISO: понедельник = 1, воскресенье = 7. По этому числу и сортируем, получая естественный порядок недели.

Тонкий момент, на котором спотыкаются: раз в ORDER BY участвует extract(isodow ...), а в SELECT его нет, это выражение обязано попасть в GROUP BY. Иначе PostgreSQL не сможет сортировать группы по полю, которого в группировке нет. Поэтому в GROUP BY стоят оба: и текстовое имя дня, и его числовой номер — они однозначно связаны, так что группы не дробятся.

Почему isodow, а не dow? У обычного dow воскресенье = 0, и неделя начинается с воскресенья — американская традиция. isodow начинает с понедельника, как привычно в России. Мелочь, но на реальном отчёте она сдвигает всю картину.

COUNT(*) считает выдачи в каждый день недели. На выходе — до семи строк, по одной на день, выстроенных от понедельника к воскресенью.

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

weekday | rentals
--- | ---
Monday    | 2247
Tuesday   | 2463
Wednesday | 2231
Thursday  | 2200
Friday    | 2272
Saturday  | 2311
Sunday    | 2320

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

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

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

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

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