从 SQL 到 SPL:按次序做区间数据的去重计数
teradata 库表有 3 个字段,日期、账号、账号购买的商品名称。
Date |
ACCOUNT |
NAME |
2024-01-01 |
A |
XOXO |
2024-01-02 |
A |
XOXO |
2024-01-02 |
A |
OXXO |
2024-01-04 |
A |
XOOX |
2024-01-05 |
A |
OOXO |
2024-01-06 |
A |
XOXO |
2024-01-01 |
B |
B11 |
2024-01-02 |
B |
B21 |
2024-01-02 |
B |
B21 |
2024-01-02 |
B |
B22 |
2024-01-02 |
B |
B11 |
2024-01-03 |
B |
B31 |
2024-01-01 |
C |
C1 |
2024-01-02 |
C |
C1 |
2024-01-03 |
C |
C1 |
现在要计算出每个账号到每天之前曾经购买过多少种商品,也就是从开始到上一日购买过的不同的商品的数量。
Date |
ACCOUNT |
COUNT_DISTINCT_NAME |
2024-01-01 |
A |
Null |
2024-01-02 |
A |
1 |
2024-01-04 |
A |
2 |
2024-01-05 |
A |
3 |
2024-01-06 |
A |
4 |
2024-01-01 |
B |
Null |
2024-01-02 |
B |
1 |
2024-01-03 |
B |
3 |
2024-01-01 |
C |
null |
2024-01-02 |
C |
1 |
2024-01-03 |
C |
1 |
按ACCOUNT分组,再按日期分组,依次处理每组,按区间取第一组到当前组,并进行去重和计数。但 SQL 分组必须伴随聚合,而不能保持分组子集做进一步处理;这时候就要转换思路,设置各种标记来过渡,写成多层嵌套语句反复遍历数据表才能计算出来。
SPL允许分组时保持分组子集,以进一步处理。SPL 的跨行引用也比窗口函数要简洁很多:
A |
|
1 |
=teraJDBC.query("select * from tb”) |
2 |
=A1.group(ACCOUNT) |
3 |
=A2.conj(~.group(Date;ACCOUNT,~[:-1].conj().icount(NAME):COUNT_DISTINCT_NAME)) |
4 |
=A3.run(if(#3==0,#3=null)) |
A1:通过JDBC加载数据。
A2:按账号分组。
A3:处理A2的每组数据:继续按日期分组,处理每日数据,取从开始到上一日的各小组数据,合并各小组,求不同商品名称的数量。最后合并各大组的处理结果。[:-1]表示从第一个成员直到上一个成员的集合,函数icount用于去重计数,即count(distinct)
A4:将第3列中的0改为null。
英文版 https://c.scudata.com/article/1734086475802