Về cơ bản, bạn cần một chức năng cửa sổ. Đó là một tính năng tiêu chuẩn ngày nay. Ngoài các chức năng cửa sổ chính hãng, bạn có thể sử dụng bất kỳ chức năng tổng hợp như chức năng cửa sổ trong Postgres bằng cách thêm một OVER
mệnh đề.
Khó khăn đặc biệt ở đây là để có được các phân vùng và sắp xếp đúng thứ tự:
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;
Và không GROUP BY
.
Tổng cho mỗi hàng được tính từ hàng đầu tiên trong phân vùng đến hàng hiện tại - hoặc trích dẫn chính xác hướng dẫn sử dụng:
Tùy chọn khung mặc định là
RANGE UNBOUNDED PRECEDING
, giống vớiRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
. VớiORDER BY
, điều này đặt khung là tất cả các hàng từ phân vùng bắt đầu lên đếnORDER BY
cuối cùng của hàng hiện tại ngang hàng .
... là số tiền tích lũy hoặc đang chạy mà bạn đang theo đuổi. Nhấn mạnh đậm của tôi.
Các hàng có cùng (circle_id, ea_year, ea_month)
là "đồng nghiệp" trong truy vấn này. Tất cả chúng hiển thị cùng một tổng đang chạy với tất cả các đồng nghiệp được thêm vào tổng. Nhưng tôi cho rằng bảng của bạn là UNIQUE
trên (circle_id, ea_year, ea_month)
, thì thứ tự sắp xếp là xác định và không có hàng nào có hàng ngang hàng.
Postgres 11 đã thêm các công cụ để bao gồm / loại trừ các công cụ ngang hàng với frame_exclusion
mới tùy chọn. Xem:
- Tổng hợp tất cả các giá trị không cùng nhóm
Bây giờ, ORDER BY ... ea_month
sẽ không hoạt động với các chuỗi cho tên tháng . Postgres sẽ sắp xếp theo thứ tự bảng chữ cái theo cài đặt ngôn ngữ.
Nếu bạn có date
thực tế các giá trị được lưu trữ trong bảng của bạn, bạn có thể sắp xếp đúng cách. Nếu không, tôi khuyên bạn nên thay thế ea_year
và ea_month
với một cột duy nhất mon
thuộc loại date
trong bảng của bạn.
-
Chuyển đổi những gì bạn có với
to_date()
:to_date(ea_year || ea_month , 'YYYYMonth') AS mon
-
Để hiển thị, bạn có thể lấy các chuỗi gốc bằng
to_char()
:to_char(mon, 'Month') AS ea_month to_char(mon, 'YYYY') AS ea_year
Trong khi mắc kẹt với thiết kế đáng tiếc, điều này sẽ hoạt động:
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;