PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Postgres-Fensterfunktion und Gruppieren nach Ausnahme

Du bist nicht , tatsächlich unter Verwendung von Aggregatfunktionen. Sie verwenden Fensterfunktionen . Deshalb verlangt PostgreSQL sp.payout und s.buyin in GROUP BY einzuschließen Klausel.

Durch Anhängen eines OVER -Klausel, die Aggregatfunktion sum() wird in eine Fensterfunktion umgewandelt, die Werte pro Partition aggregiert und dabei behält alle Zeilen.

Sie können Fensterfunktionen und Aggregatfunktionen kombinieren . Aggregationen werden zuerst angewendet. Ich habe aus Ihrer Beschreibung nicht verstanden, wie Sie mit mehreren Auszahlungen / Buy-Ins pro Ereignis umgehen möchten. Als Schätzung berechne ich eine Summe davon pro Ereignis. Jetzt Ich kann sp.payout entfernen und s.buyin aus GROUP BY -Klausel und erhalte eine Zeile pro player und event :

SELECT p.name
     , e.event_id
     , e.date
     , sum(sum(sp.payout)) OVER w
     - sum(sum(s.buyin  )) OVER w AS "Profit/Loss" 
FROM   player            p
JOIN   result            r ON r.player_id     = p.player_id  
JOIN   game              g ON g.game_id       = r.game_id 
JOIN   event             e ON e.event_id      = g.event_id 
JOIN   structure         s ON s.structure_id  = g.structure_id 
JOIN   structure_payout sp ON sp.structure_id = g.structure_id
                          AND sp.position     = r.position
WHERE  p.player_id = 17 
GROUP  BY e.event_id
WINDOW w AS (ORDER BY e.date, e.event_id)
ORDER  BY e.date, e.event_id;

In diesem Ausdruck:sum(sum(sp.payout)) OVER w , die äußere sum() ist eine Fensterfunktion, die innere sum() ist eine Aggregatfunktion.

Angenommen p.player_id und e.event_id sind PRIMARY KEY in den jeweiligen Tabellen.

Ich habe e.event_id hinzugefügt zum ORDER BY des WINDOW -Klausel, um zu einer deterministischen Sortierreihenfolge zu gelangen. (Es können mehrere Ereignisse am selben Datum stattfinden.) Ebenfalls enthalten:event_id im Ergebnis, um mehrere Ereignisse pro Tag zu unterscheiden.

Während sich die Abfrage auf eine einzelne beschränkt Spieler (WHERE p.player_id = 17 ), müssen wir p.name nicht hinzufügen oder p.player_id zu GROUP BY und ORDER BY . Wenn einer der Joins Zeilen übermäßig multiplizieren würde, wäre die resultierende Summe falsch (teilweise oder vollständig multipliziert). Gruppierung nach p.name konnte die Abfrage dann nicht reparieren.

Ich habe auch e.date entfernt aus GROUP BY Klausel. Der Primärschlüssel e.event_id deckt alle Spalten der Eingabezeile seit PostgreSQL 9.1 ab.

Wenn Wenn Sie die Abfrage ändern, um mehrere Spieler gleichzeitig zurückzugeben, passen Sie Folgendes an:

...
WHERE  p.player_id < 17  -- example - multiple players
GROUP  BY p.name, p.player_id, e.date, e.event_id  -- e.date and p.name redundant
WINDOW w AS (ORDER BY p.name, p.player_id, e.date, e.event_id)
ORDER  BY p.name, p.player_id, e.date, e.event_id;

Außer p.name ist eindeutig (?) definiert, gruppiert und sortiert nach player_id zusätzlich um korrekte Ergebnisse in einer deterministischen Sortierreihenfolge zu erhalten.

Ich habe nur e.date beibehalten und p.name in GROUP BY identische Sortierreihenfolge in allen Klauseln zu haben, in der Hoffnung auf einen Leistungsvorteil. Andernfalls können Sie die Spalten dort entfernen. (Ähnlich für nur e.date in der ersten Abfrage.)