Som udgangspunkt har du brug for en vinduesfunktion. Det er en standardfunktion i dag. Ud over ægte vinduesfunktioner kan du bruge hvilken som helst aggregeret funktion som vinduesfunktion i Postgres ved at tilføje en OVER
klausul.
Den særlige vanskelighed her er at få partitioner og sorteringsrækkefølge rigtigt:
SELECT ea_month, id, amount, ea_year, circle_id
, sum(amount) OVER (PARTITION BY circle_id
ORDER BY ea_year, ea_month) AS cum_amt
FROM tbl
ORDER BY circle_id, month;
Og nej GROUP BY
.
Summen for hver række beregnes fra den første række i partitionen til den nuværende række - eller citerer manualen for at være præcis:
Standardindstillingsindstillingen er RANGE UNBOUNDED PRECEDING
, hvilket er det samme som RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
. Med ORDER BY
, dette indstiller rammen til at være alle rækker fra partitionen starter op til den aktuelle rækkes sidste ORDER BY
peer .
... som er den kumulative eller løbende sum, du går efter. Fed fremhævelse mine.
Rækker med den samme (circle_id, ea_year, ea_month)
er "peers" i denne forespørgsel. Alle disse viser den samme løbende sum med alle peers tilføjet summen. Men jeg antager, at din tabel er UNIQUE
på (circle_id, ea_year, ea_month)
, så er sorteringsrækkefølgen deterministisk, og ingen række har peers.
Postgres 11 tilføjede værktøjer til at inkludere/ekskludere peers med den nye frame_exclusion
muligheder. Se:
- Aggregering af alle værdier, der ikke er i samme gruppe
Nu, ORDER BY ... ea_month
fungerer ikke med strenge for månedsnavne . Postgres ville sortere alfabetisk i henhold til lokalitetsindstillingen.
Hvis du har en faktisk date
værdier gemt i din tabel kan du sortere korrekt. Hvis ikke, foreslår jeg at erstatte ea_year
og ea_month
med en enkelt kolonne mon
af typen date
i din tabel.
-
Transformer det du har med
to_date()
:to_date(ea_year || ea_month , 'YYYYMonth') AS mon
-
Til visning kan du få originale strenge med
to_char()
:to_char(mon, 'Month') AS ea_month to_char(mon, 'YYYY') AS ea_year
Mens du sidder fast med det uheldige design, vil dette virke:
SELECT ea_month, id, amount, ea_year, circle_id
, sum(amount) OVER (PARTITION BY circle_id ORDER BY mon) AS cum_amt
FROM (SELECT *, to_date(ea_year || ea_month, 'YYYYMonth') AS mon FROM tbl)
ORDER BY circle_id, mon;