Vous n'êtes pas , en fait, en utilisant des fonctions d'agrégation. Vous utilisez des fonctions de fenêtre . C'est pourquoi PostgreSQL exige sp.payout et s.buyin à inclure dans le GROUP BY clause.
En ajoutant un OVER clause, la fonction d'agrégation sum() est transformé en une fonction de fenêtre, qui agrège les valeurs par partition tout en gardant toutes les lignes.
Vous pouvez combiner les fonctions de fenêtre et les fonctions d'agrégation . Les agrégations sont appliquées en premier. D'après votre description, je n'ai pas compris comment vous souhaitez gérer plusieurs paiements/buyins par événement. Comme une conjecture, je calcule une somme d'entre eux par événement. Maintenant Je peux supprimer sp.payout et s.buyin du GROUP BY clause et obtenez une ligne par player et 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;
Dans cette expression :sum(sum(sp.payout)) OVER w , le sum() externe est une fonction de fenêtre, le sum() interne est une fonction d'agrégation.
En supposant p.player_id et e.event_id sont PRIMARY KEY dans leurs tables respectives.
J'ai ajouté e.event_id au ORDER BY de la WINDOW clause pour arriver à un ordre de tri déterministe. (Il peut y avoir plusieurs événements à la même date.) Également inclus event_id dans le résultat pour distinguer plusieurs événements par jour.
Alors que la requête se limite à un seul joueur (WHERE p.player_id = 17 ), nous n'avons pas besoin d'ajouter p.name ou p.player_id à GROUP BY et ORDER BY . Si l'une des jointures multipliait indûment les lignes, la somme résultante serait incorrecte (multipliée partiellement ou complètement). Regroupement par p.name n'a pas pu réparer la requête alors.
J'ai également supprimé e.date du GROUP BY clause. La clé primaire e.event_id couvre toutes les colonnes de la ligne d'entrée depuis PostgreSQL 9.1.
Si vous modifiez la requête pour renvoyer plusieurs joueurs à la fois, adaptez :
...
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;
Sauf si p.name est défini unique (?), regrouper et trier par player_id en outre pour obtenir des résultats corrects dans un ordre de tri déterministe.
Je n'ai gardé que e.date et p.name dans GROUP BY pour avoir un ordre de tri identique dans toutes les clauses, en espérant un gain de performances. Sinon, vous pouvez supprimer les colonnes ici. (Similaire pour seulement e.date dans la première requête.)