PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Funkcja okna Postgres i grupowanie według wyjątków

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




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak filtrować wyniki zapytań w PostgreSQL

  2. PostgreSQL utwórz tabelę, jeśli nie istnieje

  3. Jak pisać wielką literą każdego słowa w PostgreSQL

  4. Funkcje okna:last_value(ORDER BY ... ASC) to samo co last_value(ORDER BY ... DESC)

  5. Jak zwrócić identyfikatory na wkładkach z Ibatis ( ze słowem kluczowym RETURNING )