Скользящее среднее за 3 месяца - Redshift SQL
Я пытаюсь создать 3-месячное скользящее среднее на основе некоторых данных, которые у меня есть при использовании RedShift SQL или Domo BeastMode (если кто-то знаком с этим).
Данные представлены ежедневно, но должны отображаться по месяцам. Таким образом, котировки / доходы должны быть суммированы по месяцам, а затем необходимо рассчитать 3MMA (исключая текущий месяц).
Итак, если бы цитата была в апреле, мне понадобилось бы среднее значение января, февраля, марта.
Входные данные выглядят так:
Quote Date MM/DD/YYYY Revenue
3/24/2015 61214
8/4/2015 22983
9/3/2015 30000
9/15/2015 171300
9/30/2015 112000
И мне нужен вывод, чтобы выглядеть примерно так:
Month Revenue 3MMA
Jan 2015 =Sum of Jan Rev =(Oct14 + Nov14 + Dec14) / 3
Feb 2015 =Sum of Feb Rev =(Nov14 + Dec14 + Jan15) / 3
March 2015 =Sum of Mar Rev =(Dec14 + Jan15 + Feb15) / 3
April 2015 =Sum of Apr Rev =(Jan15 + Feb15 + Mar15) / 3
May 2015 =Sum of May Rev =(Feb15 + Mar15 + Apr15) / 3
Если кто-нибудь сможет помочь, буду крайне признателен! Я застрял на этом довольно давно и понятия не имею, что я делаю, когда дело доходит до SQL LOL.
Ура, Логан.
3 ответа
Вы можете сделать это, используя агрегацию и оконные функции:
select date_trunc('month', quotedate) as mon,
sum(revenue) as mon_revenue,
avg(sum(revenue)) over (order by date_trunc('month', quotedate) rows between 2 preceding and current row) as revenue_3mon
from t
group by date_trunc('month', quotedate)
order by mon;
Примечание: здесь используется среднее значение, поэтому для первого и второго ряда оно будет делиться на 1 и 2 соответственно. Это также предполагает, что у вас есть хотя бы одна запись на каждый месяц.
РЕДАКТИРОВАТЬ:
Интересно, есть ли проблема с функциями агрегирования, смешанными с аналитическими функциями в RedShift. Является ли следующее лучше:
select m.*,
avg(mon_revenue) over (order by mon rows between 2 preceding and current row) as revenue_3mon
from (select date_trunc('month', quotedate) as mon,
sum(revenue) as mon_revenue
from t
group by date_trunc('month', quotedate)
) m
order by mon;
Вы могли бы сделать что-то вроде того, как мы создаем сегменты для скользящих 6 недель (столбец даты называется "дата"):
case
when date_trunc('week',dateadd(day,1,date)) = date_trunc('week',dateadd(day,1,current_date)) then 'CW'
when date_trunc('week',dateadd(day,1,date)) = date_trunc('week',dateadd(day,-6,current_date)) then 'LW'
when date_trunc('week',dateadd(day,1,date)) = date_trunc('week',dateadd(day,-13,current_date)) then '2W'
when date_trunc('week',dateadd(day,1,date)) = date_trunc('week',dateadd(day,-20,current_date)) then '3W'
when date_trunc('week',dateadd(day,1,date)) = date_trunc('week',dateadd(day,-27,current_date)) then '4W'
when date_trunc('week',dateadd(day,1,date)) = date_trunc('week',dateadd(day,-34,current_date)) then '5W'
when date_trunc('week',dateadd(day,1,date)) = date_trunc('week',dateadd(day,-41,current_date)) then '6W'
end as dateweek
Затем вы можете создать среднее значение на следующем шаге в потоке данных...
Вы не можете использовать агрегатные функции и аналитические функции вместе, запрос должен быть
select m.*,
avg(mon_revenue) over (order by mon rows between 3 preceding and 1 preceding row) as revenue_3mon -- using 3 preceding and 1 preceding row you exclude the current row
from (select date_trunc('month', quotedate) as mon,
sum(revenue) as mon_revenue
from t
group by date_trunc('month', quotedate)
) m
order by mon;