您好,登錄后才能下訂單哦!
從 SQL 到SPL基本查詢語法遷移 之多表操作
上一篇我們針對單表的情形了解了如何把數據計算從 SQL 查詢遷移到集算器,或者更準確地說,遷移到集算器所使用的SPL集算語言。這個遷移過程,既有相同的概念,也有不同的思路。
接下來,我們一起針對多表的情況看一下集算器和SPL語言是如何發揮更大的優勢的。
在前面的例子中,我們得到了每個雇員的銷售額,如果進一步還想知道每個雇員給出的最小折扣,那就又復雜了些。因為折扣信息在另一張訂單明細表里。急性子的朋友可能上來就要 JOIN 兩個表,然后再聚合兩個測度字段——這樣就算錯了!正確的做法應該是每個測度字段先按分組聚合出結果,之后再 JOIN。這是因為先 JOIN 的話可能導致結果中出現重復記錄。
按照這個思路寫出 SQL,并和集算器中的SPL代碼進行比較:
SQL
select t1.employeeId, salesAmount, lowestDiscount from (
select employeeId, sum(money) salesAmount from order
where orderDate>=’2012-01-01′ and orderDate<‘2012-02-01’
group by employeeId
having sum(money)>5000) t1
left join (
select employeeId, min(discount) lowestDiscount from order
join orderDetail on order.orderId=orderDetail.orderId
where orderDate>=’2012-01-01′ and orderDate<‘2012-02-01’
group by employeeId) t2
on t1.employeeId=t2.employeeId
集算器 | A |
---|---|
1 | =connect(“hsqlDB”) |
2 | =A1.query(“select * from order”) |
3 | =A2.select(orderDate>=date(“2012-01-01”) && orderDate<date(“2012-02-01”)) |
4 | =A3.group(employeeId;~.sum(money):salesAmount) |
5 | =A4.select(salesAmount>5000) |
6 | =A1.query(“select * from orderDetail”) |
7 | =join(A3:order,orderId;A6:orderDetail,orderId) |
8 | =A7.group(A7.order.employeeId:employeeId;~.min(orderDetail.discount):lowestDiscount) |
9 | =join(A5:r1,employeeId;A8:r2,employeeId) |
10 | =A9.new(r1.employeeId:employeeId,r1.salesAmount:salesAmount,r2.lowestDiscount:lowestDiscount) |
11 | >A1.close() |
A5 之前是我們做過的聚合符合條件的按雇員分組的銷售額;
A6 查出訂單明細表的所有數據;
A7 中的SPL用到了對應 SQL 的多表連接的新函數 join。join 函數把兩個表連接起來,這里它的參數的含義是:將 A3 序表起一個別名 order,A6 序表起一個別名 orderDetail,然后用兩個表各自的 orderId 作為關聯字段,觀察 A7 的結果如下:
可以看到,join 后形成的序表有 order、orderDetail 兩個字段,兩個字段的值分別直接指向了兩個原始序表的記錄,這就是說字段的值可以是復雜數據類型(包括序表、序列類型),也可以嵌套多層結構的數據,這是 SQL 語法里不允許的,也是SPL的特色和優勢之一。
下圖比較形象地說明了這種結構(長方形表示序表、橢圓形表示記錄、三角形表示關聯字段):
A8 直接用SPL中的 group 函數對這個復雜結構的序表進行分組聚合運算,獲得各個雇員曾經給出的最小折扣。
再需要注意的一點是 A3 序表被后面兩個不同的動作(A4、A7)都使用了一次,達到了中間結果復用的效果。這種方式對于越是復雜的計算,往往作用越大,可以起到類似“數據模塊化”的作用。
在 A9 中通過SPL的 join 函數把 A5(銷售額超過 5000)、A8(最小折扣)兩個序表連接起來;
最后,A10 使用 new 函數生成新的序表結構,而數據來自 A9 復雜結構記錄的不同層次位置。
A10 最終的結果如下:
簡單回顧一下,對于最后這個比較復雜的 SQL,如果你是個 SQL 高手,可能會看出第二個子查詢里的 where 并不是必須的,之所以保留它,是因為有可能會縮小處理數據的范圍,從而提升一些性能。這也是 SQL 的另一個特點,一方面需要不喘氣的一句話把整個查詢表達出來,另一方面還需要同時考慮性能優化因素,甚至即便考慮到了優化方案,也不一定能輕松、自然地描述出來。
在上面的例子中,不難體會出集算器以及SPL對分步過程的重視,每一個步驟的結果都是可以隨時觀察的,而且前面步驟的結果也可以重復利用,同時執行步驟也可以被程序員自由定制。這些特點最直接的好處是降低了學習和編碼的難度,而更本質的是符合人的自然思維,為描述復雜計算奠定了基礎。
SQL 中還有一類針對多個集合(表)的運算,就是常說的并、合、交、差(UNION、UNION ALL、INTERSECTION、MINUS),與之對應的,在SPL中表示為 &、|、^、\。
集合運算時常需要判斷一條記錄是否重復,在這個細節上,SQL 和SPL有一點區別。SPL里因為序表、記錄,以及字段的值都被看成是一個對象,所以在進行并集運算時,可以比對元素是否為同一個對象,而 SQL 的記錄是抽象的,不是一個實體對象,所以只能通過逐個比對兩條記錄的字段值來判斷是否重復。
我們來看一下實際的例子:
集算器 | A | B | |
---|---|---|---|
1 | =connect(“hsqlDB”) | ||
2 | =A1.query(“select * from order”) | ||
3 | =A2.select(orderId>10251 && orderId<10256) | =A2.select(orderId>10254 && orderId<10258) | |
4 | =A3&B3 | =A3 | B3 |
5 | =A3^B3 | =A3\B3 | |
6 | >A1.close() |
A3 序表的結果:
B3 序表的結果:
A3&B3,去掉重復合并到一起,并集運算后得到 A4 序表的結果:
A3|B3,保留重復合并到一起,合集運算后得到 B4 序表的結果:
A3^B3,取 A3 和 B3 里相同的記錄,交集運算后得到 A5 序表的結果:
A3\B3,A3 里去掉 B3 中存在的記錄,差集運算后得到 A5 序表的結果:
最后,再看兩個常用的 SQL 函數語法,我們來對比看一下SPL的實現。
SQL 中的 case when … then … else … end,在SPL中用 if 函數,語法是if(條件, 真值, 假值),下面的例子是把 employeeId<5 的分為一組,剩余的分到另一組:
SQL |
---|
select (case when employeeId<5 then 1 else 2 end) groupId, orderId from order |
集算器 | A |
---|---|
1 | =connect(“hsqlDB”) |
2 | =A1.query(“select * from order”) |
3 | =A2.new(if(employeeId<5,1,2):groupId,orderId) |
4 | >A1.close() |
SPL中仍然用 if 函數,if(條件, 真值, 假值),下面這個例子把 1000 這個特殊的值賦值給為 null 的 employeeId。
SQL |
---|
select coalesce(employeeId,1000) employeeId,orderId from order |
集算器 | A |
---|---|
1 | =connect(“hsqlDB”) |
2 | =A1.query(“select * from order”) |
3 | =A2.new(if(employeeId==null,1000,employeeId):employeeId,orderId) |
4 | >A1.close() |
看完上面這些例子,會給人一個感覺:集算器,或者其中的SPL代碼只是 SQL 的替代品,而常用的關系數據庫系統(RDBMS)本身已經是存儲能力(數據表)+ 計算能力 (SQL) 的綜合體了,還要這么一個外來的計算體系干嘛?
針對這個疑問,有兩個層面的答案。首先是數據層面,并非所有要計算的數據都在數據庫里。當你手邊有個文本、excel 或從一個網絡服務臨時得到一些數據想要計算,或者從大量終端采集上來的數據馬上要處理出結果……如果這些都不得不倒騰到數據庫里然后再計算,還真是有點太繞了,更何況還可能涉及到數據庫的安裝部署,或者權限控制等瑣碎而現實的問題。
其次是計算層面,對于很多復雜的計算過程,SQL 因為天生缺陷無法做到開發高效、維護高效、執行效高。這也是我們這篇文章最想說明的地方,SQL 的計算主要還是面向查詢,而這些對“高效”的追求,面向的是更廣泛的數據計算,這正是集算器和SPL語言所要重點改善的。
正因為有了這兩個層面的原因,集算器和SPL語言已經可以獨立于各種數據存儲形式,在“存儲”和“應用”之間,作為一個功能完整、形式靈活、部署方便的“數據計算中間件”而存在。這方面的內容,我們會在后面的章節做更多的介紹和探討。
這里,我們只是先簡單看一下集算器和SPL語言如何基于文本、Excel 等數據源進行計算。事實上,前面這些例子中的計算步驟完全不用改寫,只需要改變加載數據那一句就可以了。也就是把:
=A1.query(“select * from order”)
改為下列任意方式之一:
=file(“d:/data/order.txt”).import@t()// 從文本文件加載數據表
=file(“d:/data/orderDetail.xls”).importxls@t()// 從 excel 加載數據表
=httpfile(“ http:/ /127.0.0.1/service ”,” param1=value1¶m2=value2″) // 從 http server 加載數據表
……
很明顯,通過這種簡單明了的數據加載方式,可以將各種數據源的數據形成統一的“序表”,從而在一個計算過程里可以輕松混合使用。換句話說,不必為了計算能力而要求必須統一存儲方式。同樣的,在集算器和SPL的環境中,計算結果的存儲,也和加載數據一樣方便,也是多樣化的,可以由程序員自由選擇。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。