PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Somme cumulée des valeurs par mois, en remplissant les mois manquants

Ceci est très similaire aux autres questions, mais la meilleure requête reste délicate.

Requête de base pour obtenir rapidement la somme cumulée :

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 partie délicate consiste à remplir les mois manquants :

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;

Le implicite CROSS JOIN LATERAL nécessite Postgres 9.3+. Cela commence par le premier mois du tableau.
Pour commencer par un mois donné :

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.

Garder les mois de différentes années à part. Vous ne l'avez pas demandé, mais vous le voudrez probablement.

Notez que le "mois" dépend dans une certaine mesure du réglage du fuseau horaire de la session en cours ! Détails :

Connexe :