SQL每月滚动汇总

时间:2019-07-13 19:28:55

标签: sql postgresql

我正在尝试从以下包含交易的postgresql表计算银行帐户的每月余额:

# \d transactions
                 View "public.transactions"
 Column |       Type       | Collation | Nullable | Default 
--------+------------------+-----------+----------+---------
 year   | double precision |           |          | 
 month  | double precision |           |          | 
 bank   | text             |           |          | 
 amount | numeric          |           |          | 

在“累计金额”中,我的意思是该金额应包含从时间开始到给定月末为止的所有交易的总和,而不仅仅是给定月份的所有交易。

我想到了以下查询:

select 
    a.year, a.month, a.bank, 
    (select sum(b.amount) from transactions b 
     where b.year < a.year 
        or (b.year = a.year and b.month <= a.month)) 
from 
    transactions a 
order by 
    bank, year, month;

问题在于,每个银行每个月包含的行数与那里的交易数一样多。如果更多,那么更多,如果没有,则没有。 我想要一个查询,其中在整个时间间隔(包括第一笔和最后一笔交易)中,每个银行和每个月正好包含一行。

该怎么做?

https://rextester.com/WJP53830上可以找到示例数据集和查询,这是@a_horse_with_no_name

提供的。

3 个答案:

答案 0 :(得分:2)

您需要先生成一个月列表,然后才能将交易表外部连接到该列表。

with all_years as (
  select y.year, m.month, b.bank
  from generate_series(2010, 2019) as y(year) --<< adjust here for your desired range of years
    cross join generate_series(1,12) as m(month)
    cross join (select distinct bank from transactions) as b(bank)
)
select ay.*, sum(amount) over (partition by ay.bank order by ay.year, ay.month)
from all_years ay
  left join transactions t on (ay.year, ay.month, ay.bank) = (t.year::int, t.month::int, t.bank)
order by bank, year, month;  

与所有银行的交叉连接是必要的,因此all_years CTE还将在每个月的行中包含一个银行。

在线示例:https://rextester.com/ZZBVM16426

答案 1 :(得分:0)

这是我在Oracle 10 SQL中的建议:

select a.year,a.month,a.bank, (select sum(b.amount) from 
(select a.year as year,a.month as month,a.bank as bank,
 sum(a.amount) as amount from transactions c
 group by a.year,a.month,a.bank
) b
where b.year<a.year or (b.year=a.year and b.month<=a.month)) 
from transactions a order by bank, year, month;

答案 2 :(得分:0)

请考虑先按银行和月份汇总所有交易,然后运行窗口shirt_walk,以滚动自最早金额起的每月金额。

SUM() OVER()

如果要获得年初至今的总和,请通过将年份加到分区来调整WITH agg AS ( SELECT t.year, t.month, t.bank, SUM(t.amount) AS Sum_Amount FROM transactions t GROUP BY t.year, t.month, t.bank ) SELECT agg.year, agg.month, agg.bank, SUM(agg.Sum_Amount) OVER (PARTITION BY agg.bank ORDER BY agg.year, agg.month) AS rolling_sum FROM agg ORDER BY agg.year, agg.month, agg.bank 子句:

OVER()