Nie jesteś nie w rzeczywistości przy użyciu funkcji agregujących. Używasz funkcji okien . Dlatego PostgreSQL wymaga sp.payout i s.buyin do uwzględnienia w GROUP BY klauzula.
Dołączając OVER klauzula, funkcja agregująca sum() jest przekształcany w funkcję okna, która agreguje wartości na partycję, jednocześnie zachowując wszystkie wiersze.
Możesz łączyć funkcje okna i funkcje agregujące . Agregacje są stosowane jako pierwsze. Z twojego opisu nie zrozumiałem, jak chcesz obsłużyć wielokrotne wypłaty / wpisowe na wydarzenie. Zgaduję, że obliczam ich sumę na wydarzenie. Teraz Mogę usunąć sp.payout i s.buyin z GROUP BY klauzula i uzyskaj jeden wiersz na player i 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;
W tym wyrażeniu:sum(sum(sp.payout)) OVER w , zewnętrzna sum() to funkcja okna, wewnętrzna sum() jest funkcją agregującą.
Zakładając p.player_id i e.event_id to PRIMARY KEY w odpowiednich tabelach.
Dodałem e.event_id do ORDER BY WINDOW klauzula, aby uzyskać deterministyczny porządek sortowania. (Może być wiele wydarzeń tego samego dnia.) Uwzględniono także event_id w rezultacie, aby rozróżnić wiele wydarzeń dziennie.
Podczas gdy zapytanie ogranicza się do jednego gracz (WHERE p.player_id = 17 ), nie musimy dodawać p.name lub p.player_id do GROUP BY i ORDER BY . Gdyby jedno z połączeń niepotrzebnie mnożyło wiersze, suma wynikowa byłaby nieprawidłowa (pomnożona częściowo lub całkowicie). Grupowanie według p.name nie mógł wtedy naprawić zapytania.
Usunąłem też e.date z GROUP BY klauzula. Klucz podstawowy e.event_id obejmuje wszystkie kolumny wiersza wejściowego od wersji PostgreSQL 9.1.
Jeśli zmieniasz zapytanie, aby zwrócić wielu graczy naraz, dostosuj:
...
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;
Chyba że p.name jest zdefiniowany jako unikalny (?), grupowany i uporządkowany według player_id dodatkowo, aby uzyskać poprawne wyniki w deterministycznej kolejności sortowania.
Zachowałem tylko e.date i p.name w GROUP BY mieć identyczną kolejność sortowania we wszystkich klauzulach, mając nadzieję na poprawę wydajności. W przeciwnym razie możesz usunąć tam kolumny. (Podobne tylko dla e.date w pierwszym zapytaniu).