sql >> Databasteknik >  >> RDS >> PostgreSQL

Kumulativ summa av värden per månad, fyll i för saknade månader

Detta är väldigt likt andra frågor, men den bästa frågan är fortfarande knepig.

Grundläggande fråga för att få löpsumman snabbt:

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

Det knepiga är att fylla i för saknade månader :

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;

implicit CROSS JOIN LATERAL kräver Postgres 9.3+. Detta börjar med den första månaden i tabellen.
För att börja med en given månad :

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-fiol.

Håller månader från olika år isär. Du bad inte om det, men du kommer med största sannolikhet att vilja ha det.

Observera att "månaden" till viss del beror på tidszonsinställningen för den aktuella sessionen! Detaljer:

Relaterat:




  1. Hur man enkelt distribuerar TimescaleDB

  2. Hantera frysning i PostgreSQL

  3. MySql-frågan körs men det fungerar inte i sp

  4. Begränsade PostgreSQL-behörigheter för webbapp