带复位值的累积和然后恢复
Posted
技术标签:
【中文标题】带复位值的累积和然后恢复【英文标题】:cummulative sum with reset value and then resum 【发布时间】:2017-11-01 22:55:48 【问题描述】:我有以下数据:
lbid | lbdate | lbtype | lbamount
-----+------------+---------------+---------
1 | 2017-11-01 | Add Plafon | 20
2 | 2017-11-02 | Use Balance | 5
3 | 2017-11-03 | Add Balance | 1
4 | 2017-11-04 | Reduce Plafon | 10
5 | 2017-11-06 | Use Balance | 8
6 | 2017-11-07 | Add Balance | 2
7 | 2017-11-08 | Reduce Plafon | 5
8 | 2017-11-10 | Add Plafon | 10
9 | 2017-11-11 | Use Balance | 1
10 | 2017-11-12 | Reduce Plafon | 5
基本上我期望的最终结果是这样的:
lbid | lbdate | lbtype | lbamount | sumplafon | sumbalance
-----+------------+---------------+-----------+-----------+-------------
1 | 2017-11-01 | Add Plafon | 20 | 20 | 20
2 | 2017-11-02 | Use Balance | 5 | 20 | 15
3 | 2017-11-03 | Add Balance | 1 | 20 | 16
4 | 2017-11-04 | Reduce Plafon | 10 | 10 | 10
5 | 2017-11-06 | Use Balance | 8 | 10 | 2
6 | 2017-11-07 | Add Balance | 2 | 10 | 4
7 | 2017-11-08 | Reduce Plafon | 5 | 5 | 4
8 | 2017-11-10 | Add Plafon | 10 | 15 | 14
9 | 2017-11-11 | Use Balance | 1 | 15 | 15
10 | 2017-11-12 | Reduce Plafon | 5 | 10 | 10
sumplafon 是所有 lbamount 的总和,其中 lbtype 是 Add Balance(正)和 Reduce Balance(负,减去 sumplafon)。
我已经这样做了。
sum(
case
when "lbtype" = 'Add Plafon' then "lbamount"
when "lbtype" = 'Reduce Plafon' then -1 * "lbamount"
else 0
end
) over (order by "lbdate") sumplafon
而 sumbalance 是所有 lbamount 的总和,其中 lbtype 是 Add Plafon(正)、Use Balance(正)、Use Balance(负),但是每次找到 lbtype Reduce Plafon 时,sumbalance 将重置为 sumplafon,如果sumbalance 大于 sumplafon。
例如lbtype为Reduce Plafon的lbid 4,sumbalance为16且大于sumplafon 10,因此sumbalance需要重置为其sumplafon为10,然后再继续sumbalance的累计和。
我尝试通过先在 cte 中使用这样的计数来准备组。
count(
case when "lbtype" = 'Reduce Plafon' then 1 else null end
) over (order by "lbdate") countplafon
然后在第二个 cte 中,我通过在第一个 cte 中使用 countplafon 的分区来求和,如下所示:
sum(
case
when "lbtype" = 'Add Plafon' or "lbtype" = 'Add Balance' then "lbamount"
when "lbtype" = 'Use Balance' then -1 * "lbamount"
else 0
end
) over (partition by "countplafon" order by "lbdate") sumbalance
但结果只是从头开始重置 sumbalance,因为它使用 group by countplafon。
lbid | lbdate | lbtype | lbamount | countplafon |sumplafon | sumbalance
-----+------------+---------------+-----------+-----------+-------------|-----------
1 | 2017-11-01 | Add Plafon | 20 | 0 | 20 | 20
2 | 2017-11-02 | Use Balance | 5 | 0 | 20 | 15
3 | 2017-11-03 | Add Balance | 1 | 0 | 20 | 16
4 | 2017-11-04 | Reduce Plafon | 10 | 1 | 20 | 0
5 | 2017-11-06 | Use Balance | 8 | 1 | 20 | -8
6 | 2017-11-07 | Add Balance | 2 | 1 | 20 | -6
7 | 2017-11-08 | Reduce Plafon | 5 | 2 | 20 | 0
8 | 2017-11-10 | Add Plafon | 10 | 2 | 20 | 10
9 | 2017-11-11 | Use Balance | 1 | 2 | 20 | 9
10 | 2017-11-12 | Reduce Plafon | 5 | 3 | 20 | 0
这里是sqlfiddle。
这里是sql。
with
cte_runningnumbers1
as (
select
"lbid",
"lbdate",
"lbtype",
"lbamount",
count(
case when "lbtype" = 'Reduce Plafon' then 1 else null end
) over (order by "lbdate") countplafon,
sum(
case
when "lbtype" = 'Add Plafon' then "lbamount"
when "lbtype" = 'Reduce Plafon' then -1 * "lbamount"
else 0
end
) over (order by "lbdate") sumplafon
from "lb"
),
cte_runningnumbers2 as (
select
*,
sum(
case
when "lbtype" = 'Add Plafon' or "lbtype" = 'Add Balance' then "lbamount"
when "lbtype" = 'Use Balance' then -1 * "lbamount"
else 0
end
) over (partition by "countplafon" order by "lbdate") sumbalance
from "cte_runningnumbers1"
)
select *
from cte_runningnumbers2
我一直在关注这个SO question,但我仍然对如何解决我的问题感到困惑。
我需要做的最后一步是将它与之前的 sumbalance 或 sumplafon 相加(如果 sumbalance 大于 sumplafon),但我不知道该怎么做。谁能帮帮我?
【问题讨论】:
【参考方案1】:创建一个custom aggregate function. 将逻辑放在一个状态转换函数中:
create or replace function lb_agg_fun(sumbalance numeric, lbtype text, lbamount numeric)
returns numeric language sql as $$
select case
when lbtype in ('Add Plafon', 'Add Balance') then sumbalance + lbamount
when lbtype = 'Use Balance' then sumbalance - lbamount
else case
when lbamount < sumbalance then lbamount
else sumbalance
end
end;
$$;
Create an aggregate:
create aggregate lb_agg(text, numeric) (
sfunc = lb_agg_fun,
stype = numeric,
initcond = 0
);
并使用它:
select *, lb_agg(lbtype, lbamount) over (order by lbdate) as sumbalance
from lb;
lbid | lbdate | lbtype | lbamount | sumbalance
------+------------+---------------+----------+------------
1 | 2017-11-01 | Add Plafon | 20 | 20
2 | 2017-11-02 | Use Balance | 5 | 15
3 | 2017-11-03 | Add Balance | 1 | 16
4 | 2017-11-04 | Reduce Plafon | 10 | 10
5 | 2017-11-06 | Use Balance | 8 | 2
6 | 2017-11-07 | Add Balance | 2 | 4
7 | 2017-11-08 | Reduce Plafon | 5 | 4
8 | 2017-11-10 | Add Plafon | 10 | 14
9 | 2017-11-11 | Use Balance | 1 | 13
10 | 2017-11-12 | Reduce Plafon | 5 | 5
(10 rows)
【讨论】:
以上是关于带复位值的累积和然后恢复的主要内容,如果未能解决你的问题,请参考以下文章