← Назад к вопросам
SQL: Медиана выручки по месяцам
2.2 Middle🔥 231 комментариев
#SQL и базы данных#Статистика и математика
Условие
У вас есть таблица daily_sales:
- date (date)
- revenue (decimal)
Посчитайте медиану дневной выручки для каждого месяца.
Ожидаемый результат:
Таблица с колонками: month, median_revenue
Подсказка: используйте PERCENTILE_CONT или ранжирование.
Источник: задача на SQL
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение
Это задача на расчет медианы (50-го процентиля) выручки по месяцам. Медиана часто информативнее среднего, так как не подвергается влиянию выбросов.
Логика решения:
- Группируем по месяцам — извлекаем месяц из даты
- Рассчитываем медиану — 50-й процентиль дневной выручки в каждом месяце
- Выводим результат — месяц и медиану
SQL запрос с PERCENTILE_CONT (PostgreSQL):
SELECT
DATE_TRUNC('month', date)::date as month,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY revenue) as median_revenue
FROM daily_sales
GROUP BY DATE_TRUNC('month', date)
ORDER BY month;
Альтернативный подход с оконными функциями (универсальный):
WITH monthly_ranked AS (
SELECT
DATE_TRUNC('month', date)::date as month,
revenue,
ROW_NUMBER() OVER (PARTITION BY DATE_TRUNC('month', date) ORDER BY revenue) as rn,
COUNT(*) OVER (PARTITION BY DATE_TRUNC('month', date)) as cnt
FROM daily_sales
)
SELECT
month,
AVG(revenue) as median_revenue
FROM monthly_ranked
WHERE rn IN (FLOOR((cnt + 1) / 2.0), CEIL((cnt + 1) / 2.0))
GROUP BY month
ORDER BY month;
Вариант с дополнительной информацией:
SELECT
DATE_TRUNC('month', date)::date as month,
PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY revenue) as q1_revenue,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY revenue) as median_revenue,
PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY revenue) as q3_revenue,
AVG(revenue) as avg_revenue,
MIN(revenue) as min_revenue,
MAX(revenue) as max_revenue,
COUNT(*) as days_in_month,
PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY revenue) -
PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY revenue) as iqr
FROM daily_sales
GROUP BY DATE_TRUNC('month', date)
ORDER BY month;
Вариант для MySQL (нет PERCENTILE_CONT):
WITH monthly_data AS (
SELECT
DATE_FORMAT(date, '%Y-%m') as month,
revenue,
ROW_NUMBER() OVER (PARTITION BY DATE_FORMAT(date, '%Y-%m') ORDER BY revenue) as rn,
COUNT(*) OVER (PARTITION BY DATE_FORMAT(date, '%Y-%m')) as cnt
FROM daily_sales
)
SELECT
month,
AVG(revenue) as median_revenue
FROM monthly_data
WHERE rn = CEIL((cnt + 1) / 2) OR (cnt % 2 = 0 AND rn IN (FLOOR((cnt + 1) / 2), CEIL((cnt + 1) / 2)))
GROUP BY month
ORDER BY month;
Ключевые моменты:
PERCENTILE_CONT(0.5) — функция для расчета 50-го процентиля (медианы). Работает в PostgreSQL 9.4+.
WITHIN GROUP (ORDER BY revenue) — сортирует значения для расчета процентиля.
Медиана vs Среднее:
- Если выручка в день: 100, 110, 120, 1000, то среднее = 332.5 (искажено выбросом), медиана = 115 (репрезентативнее)
- Медиана полезна для выявления типичного дня, в отличие от среднего
IQR (Interquartile Range) — Q3 - Q1. Помогает выявить выбросы. Значение > Q3 + 1.5×IQR считается выбросом.
Применение в бизнесе:
- Прогнозирование — медиана дневной выручки более надёжна для бюджетирования
- Аномалия-детекция — день с выручкой > медиана × 2 требует анализа
- Сегментация дней — выходные vs будни по медиане дневной выручки