【和SQL对比】对分组子集做跨行运算

找出发生过连续三交易日涨停(涨幅>=10%)的股票

SQL解法


with A as
       (select 代码,交易日,
             收盘价/lag(收盘价) over(partition by 股票
                                  order by 交易日)-1 涨幅
        from 股价表),
     B as
       (select 代码,
            case when 涨幅>=0.1 and
                    lag(涨幅) over(partition by 代码
                             order by 交易日)>=0.1 and
                    lag(涨幅,2) over(partition by 代码
                             order by 交易日)>=0.1
                 then 1 else 0 end 三天连涨标志
        from A)
select distinct 代码 from B where 三天连涨标志=1

窗口函数可以计算出涨幅,再对涨幅施用窗口函数可计算出三天连涨标志,经过多层嵌套后终于可以计算出结果,多了一层分组导致复杂度陡增,还好有with把嵌套SQL写成分步计算的样子。

SPL解法

A B C D
1 =demo.query(“select * from 股价表”).group(代码).(~.sort(交易日期)) =[] 结果集在C1
2 for A1 =0
3 if A2.pselect(B2=if(close_price/close_price[-1]>=1.1,B2+1,0):3)>0 有三天涨停
4 >C1=C1|A2.代码

或用子计算语句

A B
1 =股价表.group(代码).(~.sort(交易日期))
2 ==A1.select(?) =0
3 =~.pselect(B2=if(收盘价/收盘价[-1]>=1.1,B2+1,0):3)>0
4 =A2.(代码)

天然可分步计算的SPL在多一层分组时复杂度增加有限,使用子计算语句或循环将外层剥开,内层计算就如同平时层数少的情况一样,不会带来思维上的困难。

这段代码很容易扩展成寻找有n天连续涨停,而且找到第一个连续涨停日就停止计算剩下的涨幅,相比之下,SQL的写法则很难扩展,同时窗口函数还要求必须把所有跨行计算全部算完后才能过滤。