Anda tidak , pada kenyataannya, menggunakan fungsi agregat. Anda menggunakan fungsi jendela . Itulah mengapa PostgreSQL menuntut sp.payout dan s.buyin untuk dimasukkan dalam GROUP BY klausa.
Dengan menambahkan OVER klausa, fungsi agregat sum() diubah menjadi fungsi jendela, yang menggabungkan nilai per partisi sambil menjaga semua baris.
Anda dapat menggabungkan fungsi jendela dan fungsi agregat . Agregasi diterapkan terlebih dahulu. Saya tidak mengerti dari deskripsi Anda bagaimana Anda ingin menangani beberapa pembayaran / pembelian per acara. Sebagai tebakan, saya menghitung jumlah mereka per acara. Sekarang Saya dapat menghapus sp.payout dan s.buyin dari GROUP BY klausa dan dapatkan satu baris per player dan 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;
Dalam ekspresi ini:sum(sum(sp.payout)) OVER w , bagian luar sum() adalah fungsi jendela, bagian dalam sum() adalah fungsi agregat.
Dengan asumsi p.player_id dan e.event_id adalah PRIMARY KEY di tabel masing-masing.
Saya menambahkan e.event_id ke ORDER BY dari WINDOW klausa untuk sampai pada urutan pengurutan deterministik. (Mungkin ada beberapa acara pada tanggal yang sama.) Juga termasuk event_id dalam hasil untuk membedakan beberapa peristiwa per hari.
Sementara kueri terbatas pada tunggal pemain (WHERE p.player_id = 17 ), kita tidak perlu menambahkan p.name atau p.player_id ke GROUP BY dan ORDER BY . Jika salah satu gabungan akan mengalikan baris terlalu banyak, jumlah yang dihasilkan akan salah (sebagian atau seluruhnya dikalikan). Pengelompokan berdasarkan p.name tidak dapat memperbaiki kueri saat itu.
Saya juga menghapus e.date dari GROUP BY ayat. Kunci utama e.event_id mencakup semua kolom dari baris input sejak PostgreSQL 9.1.
Jika Anda mengubah kueri untuk mengembalikan beberapa pemain sekaligus, sesuaikan:
...
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;
Kecuali p.name didefinisikan unik (?), kelompokkan dan urutkan berdasarkan player_id tambahan untuk mendapatkan hasil yang benar dalam urutan pengurutan deterministik.
Saya hanya menyimpan e.date dan p.name di GROUP BY memiliki urutan pengurutan yang identik di semua klausa, dengan harapan mendapatkan manfaat kinerja. Jika tidak, Anda dapat menghapus kolom di sana. (Mirip dengan e.date dalam kueri pertama.)