Ich möchte die kumulative oder laufende Feldmenge ermitteln und von der Bereitstellung in die Tabelle einfügen. Meine Inszenierungsstruktur sieht ungefähr so aus:
ea_month id amount ea_year circle_id
April 92570 1000 2014 1
April 92571 3000 2014 2
April 92572 2000 2014 3
March 92573 3000 2014 1
March 92574 2500 2014 2
March 92575 3750 2014 3
February 92576 2000 2014 1
February 92577 2500 2014 2
February 92578 1450 2014 3
Ich möchte, dass meine Zieltabelle ungefähr so aussieht:
ea_month id amount ea_year circle_id cum_amt
February 92576 1000 2014 1 1000
March 92573 3000 2014 1 4000
April 92570 2000 2014 1 6000
February 92577 3000 2014 2 3000
March 92574 2500 2014 2 5500
April 92571 3750 2014 2 9250
February 92578 2000 2014 3 2000
March 92575 2500 2014 3 4500
April 92572 1450 2014 3 5950
Ich bin wirklich sehr verwirrt darüber, wie ich dieses Ergebnis erzielen soll. Ich möchte dieses Ergebnis mit PostgreSQL erzielen.
Kann jemand vorschlagen, wie diese Ergebnismenge erreicht werden soll?
sql
postgresql
window-functions
analytic-functions
cumulative-sum
Yousuf Sultan
quelle
quelle
Antworten:
Grundsätzlich benötigen Sie eine Fensterfunktion . Das ist heutzutage eine Standardfunktion. Zusätzlich zu echten Fensterfunktionen können Sie in Postgres jede Aggregatfunktion als Fensterfunktion verwenden, indem Sie eine
OVER
Klausel anhängen .Die besondere Schwierigkeit besteht darin, Partitionen und Sortierreihenfolge richtig zu machen:
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;
Und nein
GROUP BY
.Die Summe für jede Zeile wird von der ersten Zeile in der Partition bis zur aktuellen Zeile berechnet - oder genauer gesagt im Handbuch :
... das ist die kumulative oder laufende Summe, nach der Sie suchen. Meine kühne Betonung.
Zeilen mit demselben
(circle_id, ea_year, ea_month)
sind "Peers" in dieser Abfrage. Alle zeigen die gleiche laufende Summe, wobei alle Peers zur Summe hinzugefügt werden. Aber ich nehme an, Ihre TabelleUNIQUE
auf(circle_id, ea_year, ea_month)
, dann ist die Sortierreihenfolge deterministisch ist und keine Zeile hat Peers.Funktioniert jetzt
ORDER BY ... ea_month
nicht mit Zeichenfolgen für Monatsnamen . Postgres würde alphabetisch nach der Ländereinstellung sortieren.Wenn Sie tatsächliche
date
Werte in Ihrer Tabelle gespeichert haben , können Sie diese ordnungsgemäß sortieren. Wenn nicht, schlage ich zu ersetzenea_year
undea_month
mit einer einzigen Spaltemon
vom Typdate
in der Tabelle.Verwandeln Sie, was Sie haben mit
to_date()
:Für die Anzeige können Sie Originalzeichenfolgen erhalten mit
to_char()
:Während mit dem unglücklichen Design stecken, wird dies funktionieren:
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;
quelle
range unbounded preceding
den gleichen Wert hat wierange between unbounded preceding and current row
. Aus diesem Grund wirdsum()
bei Verwendung als Fensterfunktion eine laufende Summe erzeugt, während andere Fensterfunktionen diesen Standardrahmen nicht haben.PARTITION
nicht immer benötigt wird, um eine laufende Summe zu erstellen): stackoverflow.com/a/5700744/175830