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腳本】

相關文章
相關標籤/搜索