Вернуть топ-3 продукта по продажам в каждой категории
Таблица sales(category, product_id, quantity, unit_price). Для каждой категории верните три самых продаваемых продукта по суммарной выручке, где выручка — SUM(quantity * unit_price). Один продукт на строку, не более трёх на категорию.
-- топ-3 продукта по выручке внутри каждой категории
Напишите запрос.
Агрегируют выручку по продукту, ранжируют внутри категории, снаружи берут топ: ROW_NUMBER() OVER (PARTITION BY category ORDER BY revenue DESC) с WHERE rn <= 3. GROUP BY ... LIMIT 3 режет глобально, не по категории.
- ✗Думать, что
LIMITограничивает строки по категории, а не глобально - ✗Использовать
HAVING COUNT(*), будто он выбирает верхние строки - ✗Считать, что
RANKвсегда даёт ровно три строки до пропуска
- →Как совпадения за третье место меняют число строк у
RANKпротивROW_NUMBER? - →Почему
GROUP BY ... LIMIT 3не решает ограничение по категории?
Агрегируют выручку по продукту, ранжируют внутри категории, затем во внешнем запросе оставляют первые три ранга. Оконный результат нельзя фильтровать в WHERE, поэтому нужен подзапрос:
SELECT category, product_id, revenue
FROM (
SELECT category, product_id,
SUM(quantity * unit_price) AS revenue,
ROW_NUMBER() OVER (PARTITION BY category
ORDER BY SUM(quantity * unit_price) DESC) AS rn
FROM sales
GROUP BY category, product_id
) t
WHERE rn <= 3
ORDER BY category, rn;
GROUP BY category ... LIMIT 3 не работает: LIMIT глобален и обрежет весь результат до трёх строк, а не по три на категорию. ROW_NUMBER гарантирует ровно три строки; RANK/DENSE_RANK при ничьих за третье место могут вернуть больше.