Среднее значение за последние три месяца для каждого месяца в запросе PostgreSQL - PullRequest
4 голосов
/ 11 ноября 2011

Я пытаюсь создать запрос в Postgresql, который будет использоваться для бюджета.

В настоящее время у меня есть список данных, сгруппированных по месяцам.

Для каждого месяца года мне нужно получить среднемесячные продажи за предыдущие три месяца. Например, в январе мне понадобятся среднемесячные продажи с октября по декабрь предыдущего года. Так что результат будет примерно таким:

1  12345.67
2  54321.56
3  242412.45

Это сгруппировано по номеру месяца.

Вот фрагмент кода из моего запроса, который даст мне продажи за текущий месяц:

LEFT JOIN (SELECT SUM((sti.cost + sti.freight) * sti.case_qty * sti.release_qty)
                  AS trsf_cost,
                  DATE_PART('month', st.invoice_dt) as month
             FROM stransitem sti, 
                  stocktrans st
            WHERE sti.invoice_no = st.invoice_no 
              AND st.invoice_dt >= date_trunc('year', current_date) 
              AND st.location_cd = 'SLC' 
              AND st.order_st != 'DEL'
         GROUP BY month) as trsf_cogs ON trsf_cogs.month = totals.month

Мне нужно еще одно объединение, которое даст мне то же самое, только усредненное за предыдущие 3 месяца, но я не уверен, как.

Это ВСЕГДА будет список с января по декабрь (1-12), начиная с января и заканчивая декабрем.

1 Ответ

1 голос
/ 11 ноября 2011

Это классическая проблема для оконной функции. Вот как это решить:

SELECT month_nr
      ,(COALESCE(m1, 0)
      + COALESCE(m2, 0)
      + COALESCE(m3, 0))
      /
      NULLIF ( CASE WHEN m1 IS NULL THEN 0 ELSE 1 END
             + CASE WHEN m2 IS NULL THEN 0 ELSE 1 END
             + CASE WHEN m3 IS NULL THEN 0 ELSE 1 END, 0) AS avg_prev_3_months
      -- or divide by 3 if 3 previous months are guaranteed or you don't care
FROM   (
    SELECT date_part('month', month) as month_nr
          ,lag(trsf_cost, 1) OVER w AS m1
          ,lag(trsf_cost, 2) OVER w AS m2
          ,lag(trsf_cost, 3) OVER w AS m3
    FROM  (
        SELECT date_part( 'month', month) as trsf_cost -- some dummy nr. for demo
                          ,month
        FROM   generate_series('2010-01-01 0:0'::timestamp
                              ,'2012-01-01 0:0'::timestamp, '1 month') month
        ) x
    WINDOW w AS (ORDER BY month)
    ) y;

Это требует, чтобы месяц не пропал ! Еще, посмотрите на этот связанный ответ:
Как сравнить текущую строку со следующей и предыдущей строкой в ​​PostgreSQL?

Вычисляет правильное среднее значение для каждый месяц . Если только два предыдущих месяца, то делятся на 2 и т. Д. Если нет пред. месяцев, результат равен NULL.

В вашем подзапросе используйте

date_trunc('month', st.invoice_dt)::date AS month

вместо

DATE_PART('month', st.invoice_dt) as month

, так что вы можете легко сортировать месяцы по годам!

Подробнее

...