Получить доступ

Как выбрать топ-N записей в каждой группе, например три самых дорогих заказа каждого клиента?

JuniorSQL для аналитикаSQL
Ещё спрашивают так:
  • Как взять последнюю запись для каждого пользователя?
Коротко

Пронумеровать строки внутри группы оконной функцией и отфильтровать номер во внешнем запросе: ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY amount DESC) и WHERE rn <= 3. Если важны «ничьи» — DENSE_RANK или RANK вместо ROW_NUMBER.

  • ROW_NUMBER при равных суммах выберет произвольный из них — добавляют второй ключ сортировки
  • В PostgreSQL для «одной последней» записи удобно DISTINCT ON
  • Альтернатива без окон — LATERAL JOIN с LIMIT (эффективно при индексе)

А ещё Коррелированный подзапрос «сколько дороже меня» работает, но медленнее

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

Почему не GROUP BY. MAX(amount) по клиенту даёт значение, но не всю строку заказа. Оконная функция сохраняет строки и позволяет выбрать нужные.

Ничьи. Если у клиента три заказа по 1000 рублей, ROW_NUMBER возьмёт два из них произвольно; DENSE_RANK ≤ 3 вернёт все заказы с тремя наибольшими различными суммами. Выбор зависит от формулировки задачи — уточнить у интервьюера.

Производительность. Окно сортирует всю таблицу по группе. Если групп много, а нужен топ-1 и есть индекс (customer_id, amount DESC), LATERAL-подзапрос с LIMIT 1 на каждого клиента может быть быстрее.

Пример

WITH ranked AS (
  SELECT o.*,
         ROW_NUMBER() OVER (PARTITION BY customer_id
                            ORDER BY amount DESC, order_id) AS rn
  FROM orders o
)
SELECT * FROM ranked WHERE rn <= 3;

-- PostgreSQL: последний заказ каждого клиента
SELECT DISTINCT ON (customer_id) *
FROM orders
ORDER BY customer_id, created_at DESC;

Что хотят услышать

  • Решение через ROW_NUMBER и фильтр снаружи.
  • Обработка равных значений.
  • Альтернативы: DISTINCT ON, LATERAL.

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем