Топ-5 клиентов по выручке
Задача
Ты аналитик в сети видеопроката (да, ещё остались такие). Менеджер просит: «Дай топ-5 клиентов по сумме платежей — хотим им предложить персональную скидку, чтобы не ушли к конкурентам».
Нужен список из 5 клиентов с максимальной суммарной выручкой: имя, фамилия и сумма.
Схема данных
Работаем с учебной базой проката фильмов dvdrental. Тебе понадобятся две таблицы:
customer(customer_id, first_name, last_name, ...)— клиенты.payment(payment_id, customer_id, amount, payment_date, ...)— платежи; один клиент может встречаться много раз.
Связь простая: payment.customer_id ссылается на customer.customer_id.
Решение
SELECT c.first_name, c.last_name, sum(p.amount) AS revenue
FROM payment p
JOIN customer c USING (customer_id)
GROUP BY c.customer_id, c.first_name, c.last_name
ORDER BY revenue DESC
LIMIT 5;
Разбор
Первая мысль у джуна обычно такая: «сложить amount по customer_id» — и это правильная мысль, вопрос только в деталях.
Джойн через USING (customer_id) — сокращённая форма ON p.customer_id = c.customer_id, работает, когда имя колонки совпадает в обеих таблицах. Дальше — GROUP BY: в него нужно положить не только customer_id, но и first_name/last_name, иначе PostgreSQL честно скажет column "c.first_name" must appear in the GROUP BY clause — движок не может угадать, какое из имён показывать для группы, даже если по факту оно одно на группу.
SUM(p.amount) считает суммарную выручку по группе — именно то, что просил менеджер, а не средний чек (для него была бы AVG). Дальше ORDER BY revenue DESC — сортируем по алиасу агрегата, PostgreSQL это разрешает в отличие от WHERE. И LIMIT 5 — берём только первую пятёрку.
Частая ошибка — попытаться отфильтровать топ через WHERE revenue > ...: WHERE выполняется до группировки, агрегат там ещё не существует. Если бы нужно было отсечь клиентов с выручкой меньше порога уже после группировки — использовали бы HAVING, но здесь достаточно ORDER BY + LIMIT.
Похожая логика группировки разбирается в задаче «сколько фильмов длиннее двух часов» — там, правда, агрегат без группировки, на всю таблицу целиком.
Ожидаемый результат
first_name | last_name | revenue
--- | --- | ---
Eleanor | Hunt | 211.55
Karl | Seal | 208.58
Marion | Snyder | 194.61
Rhonda | Kennedy | 191.62
Clara | Shaw | 189.60
Прорешай такие задачи сам
Читать разбор полезно, а настоящая прокачка — самому писать запросы и получать обратную связь. В симуляторе живая база и проверка запросов, лёгкий режим — бесплатно.
Прорешать в бесплатной песочнице