sql >> Database teknologi >  >> RDS >> PostgreSQL

Postgres vinduesfunktion og gruppe efter undtagelse

Du er ikke , faktisk ved at bruge aggregerede funktioner. Du bruger vinduefunktioner . Det er derfor PostgreSQL kræver sp.payout og s.buyin skal inkluderes i GROUP BY klausul.

Ved at tilføje en OVER klausul, den samlede funktion sum() omdannes til en vinduesfunktion, som samler værdier pr. partition, mens den beholder alle rækker.

Du kan kombinere vinduesfunktioner og aggregerede funktioner . Aggregeringer anvendes først. Jeg forstod ikke ud fra din beskrivelse, hvordan du vil håndtere flere udbetalinger/indkøb pr. begivenhed. Som et gæt beregner jeg en sum af dem pr. begivenhed. Nu Jeg kan fjerne sp.payout og s.buyin fra GROUP BY klausul og få en række pr. player og 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 dette udtryk:sum(sum(sp.payout)) OVER w , den ydre sum() er en vinduesfunktion, den indre sum() er en aggregeret funktion.

Forudsat p.player_id og e.event_id er PRIMARY KEY i deres respektive tabeller.

Jeg tilføjede e.event_id til ORDER BY af WINDOW klausul for at nå frem til en deterministisk sorteringsrækkefølge. (Der kan være flere begivenheder på samme dato.) Inkluderede også event_id i resultatet for at skelne mellem flere begivenheder pr. dag.

Mens forespørgslen begrænser sig til en enkelt afspiller (WHERE p.player_id = 17 ), behøver vi ikke tilføje p.name eller p.player_id til GROUP BY og ORDER BY . Hvis en af ​​joinforbindelserne ville gange rækker unødigt, ville den resulterende sum være forkert (delvist eller fuldstændig ganget). Gruppering efter p.name kunne ikke reparere forespørgslen derefter.

Jeg fjernede også e.date fra GROUP BY klausul. Den primære nøgle e.event_id dækker alle kolonner i inputrækken siden PostgreSQL 9.1.

Hvis du ændrer forespørgslen for at returnere flere spillere på én gang, tilpasse:

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

Medmindre p.name er defineret unikt (?), gruppe og rækkefølge efter player_id desuden for at få korrekte resultater i en deterministisk sorteringsrækkefølge.

Jeg beholdt kun e.date og p.name i GROUP BY at have identisk sorteringsrækkefølge i alle klausuler, i håb om en præstationsfordel. Ellers kan du fjerne kolonnerne der. (Tilsvarende for kun e.date i den første forespørgsel.)




  1. Enkel måde at beregne medianen med MySQL

  2. Hvordan bruger man et ALIAS i en PostgreSQL ORDER BY-klausul?

  3. Indstil tegnsættet og samlingen af ​​en kolonne i MariaDB

  4. Typecast streng til heltal