在數(shù)據(jù)庫應(yīng)用開發(fā)中,我們經(jīng)常需要面對復(fù)雜的SQL式計算,比如多層分組中的關(guān)聯(lián)計算。在SQL中,分組必須同時進行匯總計算,并且不能進行對象式關(guān)聯(lián)訪問,因此處理這類問題會比較復(fù)雜,只能用窗口函數(shù)嵌套多層子查詢這類高級技巧來實現(xiàn)。而本文要介紹的SPL能夠支持真正的分組,進行直觀的對象式關(guān)聯(lián)訪問,從而解決這類問題更加容易。 分組關(guān)聯(lián)在實際業(yè)務(wù)中遇到的很多,下面以實際業(yè)務(wù)為藍本設(shè)計一個比較通用的例子,以此說明SPL實現(xiàn)分組關(guān)聯(lián)的具體過程: 計算目標:查詢出缺貨的DVD分店,即現(xiàn)存的DVD拷貝不到4類的分店。 數(shù)據(jù)結(jié)構(gòu): l Branch表,存儲DVD分店信息; l DVD表,存儲DVD的標題及分類信息,DVD是虛擬的數(shù)據(jù),比如“變形金剛4”是一個DVD,但它不是一張可見的光盤 l DVDCopy表,存儲DVD的多張拷貝,DVD拷貝是真正的光盤,以實體形式存放于各個分店。注意:DVDCopy表以BranchID字段和Branch表關(guān)聯(lián),以DVDID字段和DVD表關(guān)聯(lián)。 下面是部分數(shù)據(jù)示例: Branch表:
DVD表:
DVDCopy表:
說明: 1. 計算結(jié)果應(yīng)當是Branch表中的某些記錄。 2. DVDCopy表中的Status字段如果是“Miss”,則說明光盤丟失。LastDateReturned字段如果為空,則說明光盤借出尚未歸還。顯然,丟失或未歸還的光盤不在計算范圍內(nèi),應(yīng)當過濾掉。 3. 應(yīng)當考慮某些分店可能在DVDCopy表中不存在記錄,雖然這種情況比較罕見。 解題思路: 1. 從DVDCopy表過濾出店里現(xiàn)存的DVD拷貝(沒有丟失或借出)。 2. 按照BID對DVDCopy表分組,每組就是一個門店所有的DVD拷貝。 3. 找到每個門店的DVD拷貝對應(yīng)的DVD,再計算出這些DVD的分類數(shù)量。 4. 查詢出現(xiàn)存的DVD分類數(shù)量小于4的門店,這樣的門店符合要求。 5. 找到DVDCopy表中沒出現(xiàn)過的門店,這樣的門店也符合要求。 6. 將兩類符合要求的門店合并。 SPL代碼:
A1-A3:從數(shù)據(jù)庫中檢索數(shù)據(jù),分別命名為變量Branch、DVD、DVDCopy。計算結(jié)果如下: A4:=DVDCopy.switch(DVDID,DVD:DVDID; BID,Branch:BID) 使用函數(shù)switch,將DVDCopy表中的DVDID字段切換成DVD表中對應(yīng)的記錄,將BID字段切換成Branch表中對應(yīng)的記錄。這一步是對象式關(guān)聯(lián)訪問的基礎(chǔ),計算后DVDCopy的結(jié)果如下: 淺藍色字體表示該字段對應(yīng)為某條記錄,點擊后可查看,如下圖: 此時,只需用操作符“.”就可以進行對象式關(guān)聯(lián)訪問,比如DVDCopy.(DVDID). (CATEGORY)表示每個DVD拷貝對應(yīng)的DVD分類。DVDCopy.(BID)則可以取得每個DVD拷貝對應(yīng)的分店詳情(完整記錄)。 A5:=DVDCopy.select(STATUS!="Miss" && LASTDATERETURNED!=null) 這句代碼用來過濾數(shù)據(jù),即:丟失的,未歸還的DVD拷貝不在計算范圍內(nèi),過濾后A5的值如下: A6:=A5.group(BID) 上述代碼用來對A5中的數(shù)據(jù)按照BID分組,每行代表一個門店的所有DVD拷貝,如下: 點擊淺藍色字體,可以看到組內(nèi)成員: 可以看到,函數(shù)group只對數(shù)據(jù)進行分組,并不會同時進行匯總計算,這一點和SQL中的分組函數(shù)不同。當我們需要對分組后的數(shù)據(jù)進行較深入加工,而不是簡單匯總時,用SPL的group函數(shù)會更方便,比如A7中的代碼。 A7:=A6.new(~.BID:BonList, ~.(DVDID).id(CATEGORY).count():CatCount) 上述代碼用來計算每個門店對應(yīng)的DVD拷貝各有幾類。函數(shù)new可以根據(jù)A6中的數(shù)據(jù)生成新的對象A7,A7有兩個列:BonList和CatCount,BonList直接來自A6中組內(nèi)數(shù)據(jù)的BID列,CatCount來自于組內(nèi)數(shù)據(jù)的DVDID列。CatCount的算法分為三部分:~.(DVDID)找到每個門店所有的DVD拷貝對應(yīng)的DVD記錄;id(CATEGORY)去除這些DVD記錄中重復(fù)的Category;count()用來計算Category的數(shù)量。計算結(jié)果如下: 即:B002門店有3類DVD拷貝,B003門店有3類,B001門店有4類。 A8:A7.select(CatCount<4) 上述代碼執(zhí)行查詢,求出CatCount小于4的門店,結(jié)果如下: 上述缺貨的門店是根據(jù)DVDCopy表計算出的。但有些嚴重缺貨的門店也許不會出現(xiàn)在DVDCopy表,比如該門店所有的DVD拷貝都借出去了,或者該門店完全沒有DVD拷貝,因此要把這部分門店合并進來,代碼如下: A9:=A8.(BonList) | (Branch \ A7.(BonList)) 上述代碼中,運算符“|”表示將兩個數(shù)據(jù)集進行并集計算(可用union函數(shù)代替),運算符“\”表示差集計算(可用函數(shù)diff代替)。A8.(BonList)、Branch、A7.(BonList)分別代表:DVDCopy表中缺貨的門店、所有的門店、DVDCopy表中出現(xiàn)過的門店,其值分別為:
A9就是本案例最終的計算結(jié)果,其值為: A10:>file("shortage.xlsx").xlsexport@t(A9) 最后將結(jié)果導(dǎo)出到excel文件shortage.xlsx,打開文件查看結(jié)果如下: 通過這個例子我們可以看到,SQL缺乏顯式集合,不能用A8或Branch這樣的變量來代表數(shù)據(jù)集,因此上述簡短的SPL代碼必須用幾個冗長的SQL才能實現(xiàn)。 另外,SPL可被報表工具或java程序調(diào)用,調(diào)用的方法也和普通數(shù)據(jù)庫相似,使用它提供的JDBC接口即可向java主程序返回ResultSet形式的計算結(jié)果,具體方法可參考相關(guān)文檔。 |
|
來自: raqsoft > 《集算器&潤乾報表》