sql >> Databasteknik >  >> RDS >> PostgreSQL

Postgres fönsterfunktion och grupp efter undantag

Du är inte , faktiskt med hjälp av aggregerade funktioner. Du använder fönsterfunktioner . Det är därför PostgreSQL kräver sp.payout och s.buyin inkluderas i GROUP BY klausul.

Genom att lägga till en OVER sats, den aggregerade funktionen sum() förvandlas till en fönsterfunktion, som aggregerar värden per partition medan den behålls alla rader.

Du kan kombinera fönsterfunktioner och aggregerade funktioner . Aggregeringar tillämpas först. Jag förstod inte av din beskrivning hur du vill hantera flera utbetalningar/inköp per event. Som en gissning räknar jag ut en summa av dem per händelse. Nu Jag kan ta bort sp.payout och s.buyin från GROUP BY och få en rad per player och 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;

I detta uttryck:sum(sum(sp.payout)) OVER w , den yttre sum() är en fönsterfunktion, den inre sum() är en aggregerad funktion.

Förutsatt p.player_id och e.event_id är PRIMARY KEY i sina respektive tabeller.

Jag lade till e.event_id till ORDER BY i WINDOW klausul för att komma fram till en deterministisk sorteringsordning. (Det kan finnas flera händelser på samma datum.) Inkluderade även event_id i resultatet för att särskilja flera händelser per dag.

Medan frågan begränsas till en enkel spelare (WHERE p.player_id = 17 ), behöver vi inte lägga till p.name eller p.player_id till GROUP BY och ORDER BY . Om en av kopplingarna skulle multiplicera rader i onödan, skulle den resulterande summan bli felaktig (delvis eller helt multiplicerad). Gruppering efter p.name kunde inte reparera frågan då.

Jag tog också bort e.date från GROUP BY klausul. Den primära nyckeln e.event_id täcker alla kolumner i inmatningsraden sedan PostgreSQL 9.1.

Om du ändrar frågan för att returnera flera spelare samtidigt, anpassa:

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

Såvida inte p.name definieras unikt (?), grupp och ordning efter player_id dessutom för att få korrekta resultat i en deterministisk sorteringsordning.

Jag behöll bara e.date och p.name i GROUP BY att ha identisk sorteringsordning i alla klausuler, i hopp om en prestationsfördel. Annars kan du ta bort kolumnerna där. (Liknande för bara e.date i den första frågan.)




  1. Bootstrappa SQL Express från WiX?

  2. Hantera MySQL med phpMyAdmin på Ubuntu 9.10 (Karmic)

  3. Olaglig instruktion:4 när du kör Django

  4. Hur man hämtar ett OBJECT_NAME() från en annan databas i SQL Server