从 SQL 到 SPL:分组后计算相邻子集的交集数量
某库表记录了一个项目的执行情况,每天有多人参与项目,一个人可以在一天里参与项目的多个任务。
EMP_ID |
EMP_DATE |
EMP_TASK |
A1 |
04-01-2024 |
345 |
A2 |
04-01-2024 |
546 |
A3 |
04-01-2024 |
232 |
A4 |
04-01-2024 |
8000 |
A5 |
04-01-2024 |
2344 |
A1 |
04-02-2024 |
456 |
A2 |
04-02-2024 |
9280 |
A3 |
04-02-2024 |
324 |
A2 |
04-02-2024 |
754 |
A8 |
04-02-2024 |
75 |
A2 |
04-03-2024 |
400 |
A3 |
04-03-2024 |
234 |
A3 |
04-04-2024 |
100 |
现在要计算出:每天还有几个人是昨天参与过项目的。也就是按日期分组后,计算每日与上一日的人员的交集的数量。第一天是特殊的,要假设全员上一日都参加了项目。
EMP_DATE |
COUNT |
04-01-2024 |
5 |
04-02-2024 |
3 |
04-03-2024 |
2 |
04-04-2024 |
1 |
可以先按日期分组,再对分组子集进行交集运算,这就要求在分组后保持子集。但 SQL 分组后必须立刻汇总,无法保持子集,计算交集也无从谈起。要反过来按人分组,判断每个人在某日期和上一日是否同时出现过,然后再对这些日期分组汇总,会涉及多层嵌套和窗口函数,非常麻烦。
SPL 分组后可以保持子集,也支持引用相邻子集,可以按思路直接写出代码。
A |
|
1 |
=dbConn.query("select distinct EMP_ID,EMP_DATE from tb") |
2 |
=A1.group(EMP_DATE) |
3 |
=A2.new(EMP_DATE,if(#==1,~.len(),(~.(EMP_ID)^~[-1].(EMP_ID)).len()):COUNT) |
A1:从数据库加载数据,对 EMP_ID 去重。
A2:按日期分组,但不汇总。
A3:根据分组结果新建二维表。如果当前组是第 1 组,直接返回组内成员数量;如果不是第 1 组,则求当前组和上一组的 EMP_ID 的交集,再求成员数量。^ 用于求交集,[-1] 表示上一组。
问题来源:https://stackoverflow.com/questions/78324132/how-do-i-perform-recursive-search-in-oracle
大佬,group(;) 后,第 2 参数也能取到相邻子集吧? group(;~[-1])
用 new 重写一遍,有啥奥义吗?😄
英文版 https://c.scudata.com/article/1734683705250
把相邻子集写在 group 函数里肯定是可以的,放在外面主要是让 group 函数本身简单点,初学者理解起来容易些
懂了,谢谢大佬指点🙏
spl 分组类函数 group、groups…目前市面上最强,没有之一。