SQLОконные функцииMediumБесплатно

Ранг пользователей по тратам внутри города

// Условие

Для каждого пользователя посчитайте общую сумму завершённых заказов и присвойте ранг внутри его города (по убыванию суммы). Выведите city, user_id, total_spent и city_rank. Только пользователи с рангом ≤ 3 (топ-3 в каждом городе). Отсортируйте по city, затем по city_rank.

// Таблицы

sandbox.users
user_idINT
registration_dateDATE
acquisition_channelVARCHAR(20)
platformVARCHAR(10)
cityVARCHAR(50)
is_premiumBOOLEAN
sandbox.orders
order_idINT
user_idINT
order_dateTIMESTAMP
amountNUMERIC(10,2)
statusVARCHAR(20)
delivery_daysINT
promo_codeVARCHAR(20)

// Что тренирует

ROW_NUMBERPARTITION BYCTEТоп-N по группе
▶ Решить в SQL-песочнице

// Решение

Подсказка

RANK() или ROW_NUMBER() OVER (PARTITION BY city ORDER BY total_spent DESC). Фильтрация по рангу — через CTE или подзапрос, нельзя в WHERE напрямую.

Сначала попробуй сам → Показать решение
WITH user_spending AS (
  SELECT
    u.city,
    u.user_id,
    SUM(o.amount) AS total_spent,
    ROW_NUMBER() OVER (
      PARTITION BY u.city
      ORDER BY SUM(o.amount) DESC
    ) AS city_rank
  FROM sandbox.users u
  JOIN sandbox.orders o ON u.user_id = o.user_id
  WHERE o.status = 'completed'
  GROUP BY u.city, u.user_id
)
SELECT city, user_id, total_spent, city_rank
FROM user_spending
WHERE city_rank <= 3
ORDER BY city, city_rank;

Паттерн «топ-N внутри группы» — один из самых частых на собеседовании. ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...) нумерует строки внутри каждого города. Нельзя фильтровать по оконной функции напрямую в WHERE — нужна обёртка через CTE или подзапрос. RANK() тоже допустим, но при одинаковых суммах даст одинаковые ранги и может вернуть больше 3 строк.

// Похожие задачи

// Разобраться в теме

→ Оконные функции SQL