PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Somma cumulativa dei valori per mese, da compilare per i mesi mancanti

È molto simile ad altre domande, ma la query migliore è comunque complicata.

Query di base per ottenere rapidamente la somma parziale:

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);

La parte difficile è compilare i mesi mancanti :

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;

Il implicito CROSS JOIN LATERAL richiede Postgres 9.3+. Questo inizia con il primo mese nella tabella.
Per iniziare con un determinato mese :

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.

Mantenendo mesi di anni diversi a parte. Non l'hai chiesto tu, ma molto probabilmente lo vorrai.

Nota che il "mese" in una certa misura dipende dall'impostazione del fuso orario della sessione corrente! Dettagli:

Correlati: