促销期间销售额最高的销售员
这是一个百货公司的数据库问题。数据库中有两个表,一个是商店促销时间的日历,促销记录表Promotion:
一个是全年的销售员销售额表,销售记录表SalesRecord:
现在需要知道的是每次促销活动中哪位销售员的销售额最高,这样可以给那个职工发绩效奖金。
循环促销日历表,每次循环中,先从销售记录表中选出本次促销的所有销售记录,然后对其按销售员分组并求总销售额,就可以找到销售额最大的销售员,将其名字记录在新序表内,就是答案了。
A | B | |
1 | =T("Promotion.txt") | =T("SalesRecord.txt") |
2 | =create(promo_name,best_sale) | |
3 | for A1 | =B1.select(between(sale_date, A3.start_date:A3.end_date)) |
4 | =B3.groups(clerk_name; sum(sale_amt):total_amt) | |
5 | =B4.maxp@a(total_amt) | |
6 | >A2.insert(0,A3.promo_name,B5.(clerk_name).concat@c()) |
https://try.esproc.com/splx?3by
A1获得每次促销活动的信息,B1销售记录表。
A2建立结果序表,准备记录每次促销活动的名称及销售额最高的销售员。
A3循环每次销售活动。
在循环体中,B3找到时间位于促销期间的销售数据。B4将这些销售数据按销售员分组汇总,计算每人的销售额。B5选出其中销售额最大的销售员,考虑到有可能出现多位销售员销售额相同的情况,加了@a选项。B6在结果序表中增加本次促销活动的结果,包括促销活动名称和最佳销售员。
循环结束后,在A2中可以得到最终结果:
熟练之后,A2之后的代码可以写为
=A1.new(promo_name, B1.select(between(sale_date, start_date:end_date)).groups(clerk_name; sum(sale_amt): total_amt).maxp@a(total_amt).(clerk_name).concat@c():best_sale),用循环函数代替后面的循环体,得到的结果是相同的。
Promotiontxt
SalesRecordtxt
这个题能改写成 "遍历复用" 吗?B3 格中对 SalesRecord 表全表遍历了 A1.len() 次。
遍历是必要的,需要判断每条销售数据所处的促销活动,M 条销售数据,N 个促销活动,实际上都会需要 MN 次循环,考虑到促销活动无重复区间,那预期次数是 MN/2。如果数据按时间排序的话,那还可以优化,但是排序本身是件比较复杂的事。
谢谢大佬回复…遍历复用我尝试折腾了一下,假设 SalesRecord 有 3 千万行,但以下语句执行快的原因是因为 cursor@mt(), 本机大概 9 秒左右,如果不用多线程得 30 秒左右。那这样写,事实表 SalesRecord 遍历了多少回?
感觉遍历次数应该没区别,仍然会是每个管道都需要遍历一次。但是在处理流程上,相当于用多个线程去同时用结果执行遍历,所以性能上会有很大优势。遍历复用一般适用于有限复用的情况,在这个例子里要求 Promotion 是数据不大的时候,不是很适合普遍情况。
确实,如果要写 n 个管道,估计也会很繁,我只是想尝试一下遍历复用如何写。从运行结果来看,写法应该没问题,但按你的说法,每一个管道都遍历一次,跟我想的不一样,我一直以为所有管道只需一次遍历,就像快递行业的分拣机制,一批包裹过来,随着机器履带的运行,会按照目的地一次就能分拣完。
实战中,从一个大事实表中筛选出一些记录计算是很常见的,大部分的编程写法就是 for 循环加全表遍历 n 次。spl 的遍历复用无疑是一种很新颖的手法,但从当前的写法来看,似乎起作用的是因为多线程,而不是因为遍历复用。比如改成以下写法,事实表 3650 万行,本机跑完 40 秒左右出结果,跟不用多线程的遍历复用差不了多少:
如果本案例中 SalesRecord 不能进内存序表,Poromotion 表的记录很少,10 行以内,该如何编写代码?大佬能否指导一下🙏
所有管道确实需要一次遍历,但是只是读硬盘少了,而各个管道中仍然需要各自的计算,所以总的计算量并不会少。相当于一次遍历,但是做了更多的事情。这种方式只是减少了读硬盘的过程,而并不是减少了运算量,而多管道的处理会使得并行更为有效。对于数据量比较大的情况,降低读硬盘的次数是有意义的,而用并行计算更可以提高性能。复用遍历的方式就适合有限管道的情况。
谢谢大佬花时间讲解🙏
换了一个写法,也能利用到多线程…😄 无知无畏 reckless & fearless
这种方法应该是可以的
英文版