PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Kumulierte Summe der Werte nach Monat, zum Auffüllen fehlender Monate

Dies ist anderen Fragen sehr ähnlich, aber die beste Abfrage ist immer noch knifflig.

Einfache Abfrage um schnell die laufende Summe zu bekommen:

SELECT to_char(date_trunc('month', date_added), 'Mon YYYY') AS mon_text
     , sum(sum(qty)) OVER (ORDER BY date_trunc('month', date_added)) AS running_sum
FROM   tbl
GROUP  BY date_trunc('month', date_added)
ORDER  BY date_trunc('month', date_added);

Der knifflige Teil besteht darin, fehlende Monate auszufüllen :

WITH cte AS (
   SELECT date_trunc('month', date_added) AS mon, sum(qty) AS mon_sum
   FROM   tbl
   GROUP  BY 1
   )
SELECT to_char(mon, 'Mon YYYY') AS mon_text
     , sum(c.mon_sum) OVER (ORDER BY mon) AS running_sum
FROM  (SELECT min(mon) AS min_mon FROM cte) init
     , generate_series(init.min_mon, now(), interval '1 month') mon
LEFT   JOIN cte c USING (mon)
ORDER  BY mon;

Der impliziter CROSS JOIN LATERAL erfordert Postgres 9.3+. Dies beginnt mit dem ersten Monat in der Tabelle.
Um mit einem bestimmten Monat zu beginnen :

WITH cte AS (
   SELECT date_trunc('month', date_added) AS mon, sum(qty) AS mon_sum
   FROM   tbl
   GROUP  BY 1
   )
SELECT to_char(mon, 'Mon YYYY') AS mon_text
     , COALESCE(sum(c.mon_sum) OVER (ORDER BY mon), 0) AS running_sum
FROM   generate_series('2015-01-01'::date, now(), interval '1 month') mon
LEFT   JOIN cte c USING (mon)
ORDER  BY mon;

SQL-Fiddle.

Halten Sie Monate aus verschiedenen Jahren auseinander. Sie haben nicht darum gebeten, aber Sie werden es höchstwahrscheinlich wollen.

Beachten Sie, dass der "Monat" bis zu einem gewissen Grad von der Zeitzoneneinstellung der aktuellen Sitzung abhängt! Einzelheiten:

Verwandte: