SPL 查询与报表计算实战指南 - 2 和次序位置有关的运算
2 和次序位置有关的运算
这类任务是指基于序号的、与位置相关的计算。SQL缺乏天然序号,一般要先造出序号再进行计算,代码比较难写,涉及分组后有序计算时,难度将会更大。
例1:每隔N个订单抽样选出一条
数据源:订单表。
目标:将订单表按金额排序后,依次找出第5、10、15…条记录。
SPL代码:
A |
|
1 |
$select * from Orders.txt order by OrderDate |
2 |
=A1.select(# % 5==0) |
A2:筛选出记录序号能被5整除的记录。%是除法取余数。
例2:找出每个订单离签单成功最近的那次客户接触
数据源:订单状态表(2\OrderStatus22.txt),每个订单的状态会随时间变化,状态有接触contact、停滞pause、签单sign、结束close等多种,其中sign只会出现一次。
目标:现在要在每个订单的状态里,找到 sign 之前的所有的 contact中,离 signs 最近的那条记录。
SPL代码:
A |
|
1 |
$select * from 2\OrderStatus22.txt order by EventDate |
2 |
=A1.group(OrderID) |
3 |
=A2.(~.select@c(Status!="sign").select@z1(Status=="contact")) |
A1:加载数据,按时间排序。
A2:按订单分组,但不汇总,每组是一个集合。
A3=A2.(~.select@c(Status!=“sign”)…) 处理每组数据:先过滤当前组,从第 1 个成员开始取,直到遇到使状态等于 sign 的成员。
@c是select函数的选项,用于按位置取成员,表示从第一个成员开始取,直到遇到使条件为假的成员为止。
l 知识点:函数选项和位置
SPL的很多函数都有函数选项,用于扩展函数的功能,按位置取成员是比较常用的一类,比如取第1个成员、倒排成员、第1片连续成员等等。以select函数为例。
@1:过滤结果中的第1个成员。
@z:过滤结果中倒数第1个成员。
@c: 从第1个成员往后取,直到遇到第1个非过滤结果(使条件为假的成员)时停止。
…. select@z(Status=="contact") 继续处理各组数据:过滤出状态等于Closed的成员,再倒排结果。
…@1 继续处理各组数据:取第 1 个成员。
例3:将试用产品的送出计划应用到所有销售的所有客户
数据源:试用产品计划表(TrialProductPlan.txt)用于报表呈现,其中销售员和客户是分组字段,试用产品和产品送出时间是明细。对于同一个销售来说,他需要把自己负责的每个试用产品寄给自己的每个客户,因此各小组的明细记录数相同;不同销售的明细记录数不必相同。按前3个字段排序后,在每个销售的最后一个客户的明细填上计划送出试用产品的日期,就完成了计划的制定。
目标:将每个销售员的送出计划应用到所有的客户,换句话说,把每个销售员的最后一个客户的送出日期,按顺序更新或复制到其他客户。
SPL代码:
A |
|
1 |
$select * from TrialProductPlan.txt order by SellerId,Client,TrialProduct |
2 |
=A1.group(SellerId).(~.group(Client)) |
3 |
=A2.(last=~.m(-1).(PlanDate),~.(~.(PlanDate=last(#)))) |
4 |
return A1 |
A1:加载数据,按前3个字段排序。
A2:用按销售员分组,组内再按客户分小组,但不汇总,每个大组和小组都是一个集合。函数 group 用于分组,~ 表示当前组。第 1 个销售员点击展开后如图:
A3=A2.(last=~.m(-1).(PlanDate), …) 循环处理 A2 中的每个大组,先取当前大组中的最后一个小组的 PlanDate 字段的序列,命名为 last。第一个大组的 last 如图:
函数 m 表示按序号取成员,-1 表示倒数第 1 个。
l 知识点:函数m
函数m提供了多种功能,用于取集合中指定位置的成员,并拼成新的集合。完整语法是:A.m(a:b,c,d:e) ,其中,A是长度为n的集合。-n<=a<=n且a不等于0,当1<=a<=n时,表示正数第a个成员;当-n<=a<=-1,表示倒数第a个成员。b、c、d和e规则同a一样,常用于从后往前取出序列成员。a和c在序列中位置必须在b和e的左侧。冒号左边参数省略时,缺省值为1,右边参数省略时,缺省值为-1。
(…, ~.(~.( PlanDate =last(#)))) 继续处理当前大组的每个小组的每条记录,将PlanDate改成 last 里位置相同的值。”~.(PlanDate)”表示按名字取出字段序列;”last(#)”表示按序号取成员,是”last.m(#)”的简写;符号 #表示当前序号。执行后 A1被修改成下图:
上面代码修改了每个大组的每个小组,实际上最后一个小组可以不改,或者说应该取第 1 到倒数第 2 个小组,代码:~.m(1:-2),简写做 ~.m(:-2)
A4:最后返回 A1。
扩展阅读
(https://c.raqsoft.com.cn/article/1740386718048)
(https://c.raqsoft.com.cn/article/1736157120197)
(https://c.raqsoft.com.cn/article/1744275268499)
(https://c.raqsoft.com.cn/article/1745800641250)
(https://c.raqsoft.com.cn/article/1741096770958)
(https://c.raqsoft.com.cn/article/1735093433084)
(https://c.raqsoft.com.cn/article/1736566315971)