SPL 简化 SQL 案例详解:多层固定分组

在数据库应用开发中,咱们常常须要面对各类复杂的SQL计算,多层固定分组就是其中一种。实现该算法的思路是用left join语句将源数据按照固定的依据对齐,但因为该算法每每涉及分组汇总、行间计算、填补缺失数据,并且层次较多,所以相应的SQL语句会很是复杂。java

本文将介绍一种相对简单易懂的方法,也就是用SPL实现多层固定分组。下面用一个实例进行说明:算法

表stocklog存储着天天多种货物的屡次出入库记录,表中部分数据以下:数据库

image.png

咱们指望的结果是列出指定时间段内,天天每种货物的库存状态。其中,库存状态是指天天每种产品的开库时数量(Open)、入库数量(Enter)、最高库存(Total)、出库数量(Issued)、闭库时数量(Close)。以下图所示:函数

在原表数据中,若是Indicator的值为空,则表示该记录是入库动做,若是为ISSUE,则表示出库。同时须要注意的是,实际记录日期也许有缺失,即某几天彻底没有出入库记录,但对于统计的库存状态来讲必须包含完整连续的日期。并且知足如下规则:当日的“Open”应该等于前一日的“Close”,“Enter”和“Issued”来自于表stocklog,“Total”等于“Open+Enter”,“Close”等于“Open+Enter-Issued”或者是“Total-Issued”。工具

SPL代码以下:spa

image.png

A1:查询数据库,根据表stocklog计算出每种产品天天总的入库数量和出库数量。这里只须要对数据进行分组汇总,计算上没有难度,能够交给SQL语句去完成。值得注意的是,A1中有两个参数start和end,分别对应SQL语句中的两个问号,表明外部传入的时间段,能够来自于JAVA或报表工具。假设start和end的值分别为 2014-04-01和2014-04-10,则A1的计算结果以下:excel

A2=A1.group(INAME)接口

这句代码将A1按照INAME分组,每组数据是一个产品各天的总出入库数量。值得注意的是,这里无需对分组后的数据进行汇总计算,也就是说是一个纯粹的分组操做。A2的计算结果以下图左侧,右侧是每组数据的明细。开发

关于分组,集算器SPL有两个函数:groups和group。函数groups相似于SQL中的group by语句,能够在分组的同时进行汇总。而group函数只分组,不作汇总,这种纯粹的分组功能是SQL所缺少的。rem

最终须要的计算结果是start到end之间每一天的库存状态,而源数据并不是天天都有出入库记录,所以还要把A2按照连续的时间序列对齐。下面先生成这个时间序列。

B2=periods(start,end,1)

函数periods能够生成时间序列,有三个参数:起始时间、终止时间、间隔。缺省将生成日期序列,使用选项还能够生成年、季、月、旬的时间序列。A3的计算结果以下:

A3=for A2,这是循环语句,表示对A2进行循环,每次计算一个产品。

B3-B6是循环体,具体算法是先将该产品的出入库记录与B2中的时间序列对齐,而后计算每一个产品天天的库存状态,最后将计算结果追加到B6中。值得注意的是,集算器使用直观的缩进来表示循环体,而不是括号或begin/end等标识符。B3-B6就是循环语句A3的循环体。

B3=A3.align(B2,IDATE)

这句代码将当前产品的出入库记录与B2中的时间序列对齐。注意,A3既是循环语句,也是循环变量,即当前产品的出入库记录。以产品Item3为例,下图左侧是对齐前的数据,右侧是对齐后的数据:

      

B4>c=0

这句代码用来给变量c赋初值0。c表明当前产品每条库存状态的OPENING字段,初始日期的OPENING字段为0,c会在B5中不断被修改。

B5=B3.new(A3.INAME:INAME,B2(#):IDATE, c:OPENING, ENTER,(b=c+ENTER):TOTAL,ISSUE,(c=b-ISSUE):CLOSE)

这句代码用来计算库存状态,是整个计算过程的核心。B3.new(…)表示以B3为基础新建一个序表,即当前产品的库存状态。新序表中有7个字段,分别是:

A3. INAME: INAME ----从当前产品的出入库记录A3取出INAME字段,新字段名为INAME。

B2 (#):IDATE ----将时间序列B2按顺序插入新序表,做为新字段IDATE。注意,#表示A3的记录序号,B2(N)表示B2的第N条记录,所以B2(#)表示按A3的序号将B2插入新序表。

c: OPENING ----将变量c做为OPENING的字段值,第一条记录时,这个值为0。

ENTER----将B3中的字段ENTER直接当作新字段。因为新序表是基于B3的,所以无需像INAME字段那样重命名。

(b=c+ENTER):TOTAL----按公式OPENING+ENTER计算出字段TOTAL,为了清晰起见,这里用括号把表达式括起来。

ISSUE---将B3中的字段ISSUE直接当作新字段。

(c=b-ISSUE):CLOSE---按公式TOTAL-ISSUE计算CLOSE字段。注意,这里的c已经被修改了,在计算下一条记录时,c会做为OPENING字段的值,从而知足业务规则:当日的“Open”等于前一日的“Close”。

以Item3为例,B5的计算结果以下:

B6=@|B5

这句代码将B5不断地追加到当前格中,@表示当前格B6,最终计算结果以下:

B6就是本案例的最终计算结果。

file("stocklog.xlsx").xlsexport@t(B6)

这句代码将计算结果导出到"stocklog.xlsx"文件,能够经过excel工具来查看:

另外,集算器可被报表工具或java程序调用,调用的方法也和普通数据库类似,使用它提供的JDBC接口便可向java主程序返回ResultSet形式的计算结果,具体方法可参考相关文档。【Java如何调用SPL脚本】

相关文章
相关标签/搜索