← Назад к вопросам

SQL: Топ-5 продуктов по выручке

1.0 Junior🔥 301 комментариев
#SQL и базы данных

Условие

Дана таблица продаж с полями: product_name, quantity, price.

Напишите SQL-запрос для поиска топ-5 продуктов по общей выручке.

Используйте группировку, агрегацию и сортировку.

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение

Базовый запрос: Топ-5 по выручке

SELECT 
    product_name,
    SUM(quantity * price) AS total_revenue
FROM sales
GROUP BY product_name
ORDER BY total_revenue DESC
LIMIT 5;

Объяснение:

  • SUM(quantity * price) — рассчитываем выручку как произведение количества и цены
  • GROUP BY product_name — группируем данные по названию продукта
  • ORDER BY total_revenue DESC — сортируем по выручке в убывающем порядке
  • LIMIT 5 — берём только первые 5 строк

Вариант 2: С дополнительной статистикой

Часто нужна не только выручка, но и другие метрики:

SELECT 
    product_name,
    COUNT(*) AS number_of_sales,
    SUM(quantity) AS total_quantity,
    ROUND(AVG(price), 2) AS avg_price,
    SUM(quantity * price) AS total_revenue,
    ROW_NUMBER() OVER (ORDER BY SUM(quantity * price) DESC) AS rank
FROM sales
GROUP BY product_name
ORDER BY total_revenue DESC
LIMIT 5;

Новые элементы:

  • COUNT(*) — количество транзакций
  • SUM(quantity) — общее количество единиц
  • AVG(price) — средняя цена продукта
  • ROW_NUMBER() OVER (ORDER BY ...) — ранг для визуализации позиции

Вариант 3: С фильтрацией по дате

В реальных задачах часто нужны данные за конкретный период:

SELECT 
    product_name,
    SUM(quantity * price) AS total_revenue
FROM sales
WHERE sale_date >= DATE_TRUNC('month', CURRENT_DATE) - INTERVAL '1 month'
GROUP BY product_name
ORDER BY total_revenue DESC
LIMIT 5;

Вариант 4: Со скользящим окном

Для анализа трендов:

WITH ranked_sales AS (
    SELECT 
        product_name,
        sale_date,
        quantity * price AS revenue,
        SUM(quantity * price) OVER (
            PARTITION BY product_name 
            ORDER BY sale_date 
            ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
        ) AS moving_avg_7days
    FROM sales
)
SELECT 
    product_name,
    SUM(revenue) AS total_revenue,
    ROUND(AVG(moving_avg_7days), 2) AS avg_7day_moving_avg
FROM ranked_sales
GROUP BY product_name
ORDER BY total_revenue DESC
LIMIT 5;

Вариант 5: С процентом от общей выручки

WITH product_revenue AS (
    SELECT 
        product_name,
        SUM(quantity * price) AS total_revenue
    FROM sales
    GROUP BY product_name
),
total_revenue_calc AS (
    SELECT SUM(total_revenue) AS grand_total FROM product_revenue
)
SELECT 
    pr.product_name,
    pr.total_revenue,
    ROUND(100.0 * pr.total_revenue / tr.grand_total, 2) AS revenue_percentage,
    ROW_NUMBER() OVER (ORDER BY pr.total_revenue DESC) AS rank
FROM product_revenue pr
CROSS JOIN total_revenue_calc tr
ORDER BY pr.total_revenue DESC
LIMIT 5;

Ключевые элементы SQL-запроса

GROUP BY — группирует строки по одному или нескольким столбцам. Без этого агрегатные функции работали бы на всей таблице.

Агрегатные функции:

  • SUM() — сумма значений
  • COUNT() — количество строк
  • AVG() — среднее значение
  • MIN(), MAX() — минимум и максимум

ORDER BY — сортирует результаты. DESC = по убыванию, ASC = по возрастанию.

LIMIT — ограничивает количество возвращаемых строк.

Window Functions — позволяют выполнять расчёты в окне строк без потери деталей.

Оптимизация для больших таблиц

Для таблиц с миллионами строк:

SELECT 
    product_name,
    SUM(quantity * price) AS total_revenue
FROM sales
WHERE sale_date >= CURRENT_DATE - INTERVAL '1 year'
GROUP BY product_name
ORDER BY total_revenue DESC
LIMIT 5;

Рекомендации:

  1. Используй WHERE ДО GROUP BY для фильтрации
  2. Создавай индексы на product_name и sale_date
  3. Для больших датасетов рассмотри материализованные представления
SQL: Топ-5 продуктов по выручке | PrepBro