Pada dasarnya, Anda memerlukan fungsi jendela. Itu fitur standar saat ini. Selain fungsi jendela asli, Anda dapat menggunakan apa saja fungsi agregat sebagai fungsi jendela di Postgres dengan menambahkan OVER
klausa.
Kesulitan khusus di sini adalah untuk mendapatkan partisi dan mengurutkan urutan yang benar:
SELECT ea_month, id, amount, ea_year, circle_id
, sum(amount) OVER (PARTITION BY circle_id
ORDER BY ea_year, ea_month) AS cum_amt
FROM tbl
ORDER BY circle_id, month;
Dan tidak GROUP BY
.
Jumlah untuk setiap baris dihitung dari baris pertama di partisi ke baris saat ini - atau lebih tepatnya mengutip manual:
Opsi pembingkaian default adalah
RANGE UNBOUNDED PRECEDING
, yang sama denganRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
. DenganORDER BY
, ini menetapkan bingkai menjadi semua baris dari partisimulai hinggaORDER BY
terakhir baris saat ini rekan .
... yang merupakan jumlah kumulatif atau berjalan yang Anda cari. Penekanan saya yang berani.
Baris dengan (circle_id, ea_year, ea_month)
yang sama adalah "rekan" dalam kueri ini. Semua itu menunjukkan jumlah berjalan yang sama dengan semua rekan ditambahkan ke jumlah tersebut. Tapi saya menganggap tabel Anda UNIQUE
pada (circle_id, ea_year, ea_month)
, maka urutan pengurutannya adalah deterministik dan tidak ada baris yang memiliki rekan.
Postgres 11 menambahkan alat untuk menyertakan / mengecualikan rekan dengan frame_exclusion
baru pilihan. Lihat:
- Menggabungkan semua nilai yang tidak berada dalam grup yang sama
Sekarang, ORDER BY ... ea_month
tidak akan berfungsi dengan string untuk nama bulan . Postgres akan mengurutkan berdasarkan abjad sesuai dengan pengaturan lokal.
Jika Anda memiliki date
yang sebenarnya nilai yang disimpan di tabel Anda, Anda dapat mengurutkan dengan benar. Jika tidak, saya sarankan untuk mengganti ea_year
dan ea_month
dengan satu kolom mon
jenis date
di meja Anda.
-
Ubah apa yang Anda miliki dengan
to_date()
:to_date(ea_year || ea_month , 'YYYYMonth') AS mon
-
Untuk tampilan, Anda bisa mendapatkan string asli dengan
to_char()
:to_char(mon, 'Month') AS ea_month to_char(mon, 'YYYY') AS ea_year
Saat terjebak dengan desain yang tidak menguntungkan, ini akan berhasil:
SELECT ea_month, id, amount, ea_year, circle_id
, sum(amount) OVER (PARTITION BY circle_id ORDER BY mon) AS cum_amt
FROM (SELECT *, to_date(ea_year || ea_month, 'YYYYMonth') AS mon FROM tbl)
ORDER BY circle_id, mon;