V zásadě potřebujete funkci okna. To je v dnešní době standardní funkce. Kromě originálních funkcí okna můžete použít jakékoli agregační funkci jako funkci okna v Postgresu připojením OVER doložka.
Zvláštní obtíž je zde získat správné oddíly a pořadí řazení:
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;
A ne GROUP BY .
Součet pro každý řádek se vypočítává od prvního řádku v oddílu po aktuální řádek – nebo přesněji cituji manuál:
Výchozí možnost orámování je
RANGE UNBOUNDED PRECEDING, což je totéž jakoRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. PomocíORDER BY, toto nastaví rámec tak, aby byly všechny řádky od začátku oddílu až po posledníORDER BYaktuálního řádku vrstevníka .
... což je kumulativní nebo průběžná částka, o kterou vám jde. Tučné zdůraznění moje.
Řádky se stejným (circle_id, ea_year, ea_month) jsou "peers" v tomto dotazu. Všechny vykazují stejný průběžný součet, přičemž k součtu se přidávají všichni kolegové. Ale předpokládám, že vaše tabulka je UNIQUE dne (circle_id, ea_year, ea_month) , pak je pořadí řazení deterministické a žádný řádek nemá rovnocenné.
Postgres 11 přidal nástroje pro zahrnutí / vyloučení kolegů pomocí nového frame_exclusion možnosti. Viz:
- Agregace všech hodnot, které nejsou ve stejné skupině
Nyní ORDER BY ... ea_month nebude fungovat s řetězci pro názvy měsíců . Postgres by seřadil abecedně podle nastavení národního prostředí.
Pokud máte aktuální date hodnoty uložené ve vaší tabulce můžete správně třídit. Pokud ne, doporučuji nahradit ea_year a ea_month s jedním sloupcem mon typu date ve vaší tabulce.
-
Transformujte to, co máte, pomocí
to_date():to_date(ea_year || ea_month , 'YYYYMonth') AS mon -
Pro zobrazení můžete získat originální řetězce pomocí
to_char():to_char(mon, 'Month') AS ea_month to_char(mon, 'YYYY') AS ea_year
I když zůstanete u nešťastného designu, bude to fungovat:
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;