根据条件重置的 7 天累积总和
Posted
技术标签:
【中文标题】根据条件重置的 7 天累积总和【英文标题】:7 day cumulative sum that resets on condition 【发布时间】:2018-12-21 15:57:44 【问题描述】:我正在尝试编写一个脚本来计算客户在 7 天内每次花费超过 1200 欧元的时间。一旦客户超过 1200 欧元的门槛,累计金额应重置。例如,如果客户在第 3 天超过 1200 欧元,则该金额计为 1,累计金额应在第 4 天重置。
我见过类似的问题,其中包括重置累积总和。这些解决方案均不适用于 7 天滚动条件。
示例数据集
create table test2
(
yyyymmdd DATE not null,
account_id NUMBER,
vol_eur NUMBER
);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('21-01-2018 11:16:19', 'dd-mm-yyyy hh24:mi:ss'), 57642, 1500);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('06-01-2018 09:51:23', 'dd-mm-yyyy hh24:mi:ss'), 57645, 190);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('21-01-2018 07:09:35', 'dd-mm-yyyy hh24:mi:ss'), 57645, 300);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('03-01-2018 14:58:14', 'dd-mm-yyyy hh24:mi:ss'), 57646, 1000);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('17-01-2018 13:30:44', 'dd-mm-yyyy hh24:mi:ss'), 57646, 130);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('03-01-2018 18:33:33', 'dd-mm-yyyy hh24:mi:ss'), 57647, 1000);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('04-01-2018 08:44:33', 'dd-mm-yyyy hh24:mi:ss'), 57647, 270);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('05-01-2018 19:28:08', 'dd-mm-yyyy hh24:mi:ss'), 57647, 800);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('13-01-2018 12:24:21', 'dd-mm-yyyy hh24:mi:ss'), 57647, 700);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('15-01-2018 10:52:50', 'dd-mm-yyyy hh24:mi:ss'), 57647, 1000);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('27-01-2018 12:07:20', 'dd-mm-yyyy hh24:mi:ss'), 57647, 500);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('10-01-2018 21:14:46', 'dd-mm-yyyy hh24:mi:ss'), 57647, 690);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('30-01-2018 15:39:17', 'dd-mm-yyyy hh24:mi:ss'), 57647, 5500);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('05-01-2018 19:43:38', 'dd-mm-yyyy hh24:mi:ss'), 57649, 300);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('06-01-2018 17:54:30', 'dd-mm-yyyy hh24:mi:ss'), 57649, 150);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('15-01-2018 19:38:36', 'dd-mm-yyyy hh24:mi:ss'), 57649, 1000);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('20-01-2018 13:26:34', 'dd-mm-yyyy hh24:mi:ss'), 57649, 1150);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('06-01-2018 17:09:54', 'dd-mm-yyyy hh24:mi:ss'), 57651, 300);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('28-01-2018 17:31:14', 'dd-mm-yyyy hh24:mi:ss'), 57651, 250);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('04-01-2018 13:39:06', 'dd-mm-yyyy hh24:mi:ss'), 57654, 150);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('07-01-2018 13:18:26', 'dd-mm-yyyy hh24:mi:ss'), 57654, 200);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('13-01-2018 19:44:08', 'dd-mm-yyyy hh24:mi:ss'), 57654, 150);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('21-01-2018 16:18:05', 'dd-mm-yyyy hh24:mi:ss'), 57654, 150);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('28-01-2018 10:53:03', 'dd-mm-yyyy hh24:mi:ss'), 57654, 60);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('01-01-2018 12:09:00', 'dd-mm-yyyy hh24:mi:ss'), 57655, 1000);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('01-01-2018 17:01:27', 'dd-mm-yyyy hh24:mi:ss'), 57655, 1000);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('02-01-2018 19:30:31', 'dd-mm-yyyy hh24:mi:ss'), 57655, 200);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('21-01-2018 15:52:29', 'dd-mm-yyyy hh24:mi:ss'), 57655, 1000);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('21-01-2018 16:58:52', 'dd-mm-yyyy hh24:mi:ss'), 57655, 500);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('11-01-2018 14:26:30', 'dd-mm-yyyy hh24:mi:ss'), 57661, 2000);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('12-01-2018 21:54:25', 'dd-mm-yyyy hh24:mi:ss'), 57661, 500);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('06-01-2018 16:46:25', 'dd-mm-yyyy hh24:mi:ss'), 57666, 5000);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('10-01-2018 18:27:51', 'dd-mm-yyyy hh24:mi:ss'), 57666, 5000);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('14-01-2018 18:52:14', 'dd-mm-yyyy hh24:mi:ss'), 57666, 5000);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('20-01-2018 12:19:07', 'dd-mm-yyyy hh24:mi:ss'), 57666, 5000);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('24-01-2018 18:38:40', 'dd-mm-yyyy hh24:mi:ss'), 57666, 2990);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('30-01-2018 18:36:01', 'dd-mm-yyyy hh24:mi:ss'), 57666, 1980);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('19-01-2018 18:48:44', 'dd-mm-yyyy hh24:mi:ss'), 57671, 2000);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('19-01-2018 23:41:56', 'dd-mm-yyyy hh24:mi:ss'), 57671, 100);
insert into test2 (yyyymmdd, account_id, vol_eur)
values (to_date('21-01-2018 19:22:51', 'dd-mm-yyyy hh24:mi:ss'), 57671, 5000);
commit;
【问题讨论】:
这种类型的逻辑需要分层或递归查询。您使用的是什么版本的 Oracle? 谢谢。甲骨文 12c。 最初 7 天的开始日期应该是什么?显示预期的输出会有所帮助。 每位客户的第一次购买日期 您期望输出什么?特别是,如果连续 8 天的金额为 (200, 200, 200, 200, 200, 200, 100, 400),则从第 1 天到第 7 天的总和为 1100(因此在 7 天内不超过限制),而从第 2 天到第 8 天为 1400(因此超过了 7 天的限制)。 【参考方案1】:一个带有递归 cte 的选项。
with rownums as (select t.*,row_number() over(partition by id order by dt) as rnum
from tbl t
)
,rsum as (select id,dt,val,rnum,val as cumsum,0 as dt_diff
from rownums
where rnum = 1
union all
select r.id
,r.dt
,r.val
,r.rnum
,case when dt_diff + rs.dt - r.dt > 7 then r.val
when dt_diff + rs.dt - r.dt <= 7 and r.val + rs.cumsum < 1200 then r.val+rs.cumsum
else 0 end
,case when dt_diff + rs.dt - r.dt > 7 then 0
else dt_diff + rs.dt - r.dt end
from rsum rs
join rownums r on r.id = rs.id and r.rnum = rs.rnum+1
)
select id,dt,val,case when cumsum = 0 and lag(cumsum,1) over(partition by id order by dt) <= 1200 then val+lag(cumsum,1) over(partition by id order by dt)
when cumsum = 0 and lag(cumsum,1) over(partition by id order by dt) > 1200 then val
else cumsum end as res
from rsum
order by 1,2
计算第一个 cte rownums
中每个用户 ID 的行数。
从之前定义的rownums
cte 中选择第一行作为锚行,然后遍历其余行,与锚行连接,一次向前看一行。 case
表达式在这里检查条件。
rsum
cte 将累积总和设置为0
,这表示一个新组基于 7 天内超过 1200 的总和或一个新的 7 天周期开始。使用lag
最终计算这些行的值。
Sample Demo in SQL Server
【讨论】:
以上是关于根据条件重置的 7 天累积总和的主要内容,如果未能解决你的问题,请参考以下文章