溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

淺解比 SQL 更好用的 SPL(二)

發(fā)布時間:2020-07-07 09:50:20 來源:網(wǎng)絡(luò) 閱讀:699 作者:raqsoft 欄目:大數(shù)據(jù)

從 SQL 到SPL基本查詢語法遷移 之多表操作

上一篇我們針對單表的情形了解了如何把數(shù)據(jù)計(jì)算從 SQL 查詢遷移到集算器,或者更準(zhǔn)確地說,遷移到集算器所使用的SPL集算語言。這個遷移過程,既有相同的概念,也有不同的思路。

接下來,我們一起針對多表的情況看一下集算器和SPL語言是如何發(fā)揮更大的優(yōu)勢的。

JOIN 連接兩個記錄

在前面的例子中,我們得到了每個雇員的銷售額,如果進(jìn)一步還想知道每個雇員給出的最小折扣,那就又復(fù)雜了些。因?yàn)檎劭坌畔⒃诹硪粡堄唵蚊骷?xì)表里。急性子的朋友可能上來就要 JOIN 兩個表,然后再聚合兩個測度字段——這樣就算錯了!正確的做法應(yīng)該是每個測度字段先按分組聚合出結(jié)果,之后再 JOIN。這是因?yàn)橄?JOIN 的話可能導(dǎo)致結(jié)果中出現(xiàn)重復(fù)記錄。

按照這個思路寫出 SQL,并和集算器中的SPL代碼進(jìn)行比較:

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 查出訂單明細(xì)表的所有數(shù)據(jù);

A7 中的SPL用到了對應(yīng) SQL 的多表連接的新函數(shù) join。join 函數(shù)把兩個表連接起來,這里它的參數(shù)的含義是:將 A3 序表起一個別名 order,A6 序表起一個別名 orderDetail,然后用兩個表各自的 orderId 作為關(guān)聯(lián)字段,觀察 A7 的結(jié)果如下:
淺解比 SQL 更好用的 SPL(二)

可以看到,join 后形成的序表有 order、orderDetail 兩個字段,兩個字段的值分別直接指向了兩個原始序表的記錄,這就是說字段的值可以是復(fù)雜數(shù)據(jù)類型(包括序表、序列類型),也可以嵌套多層結(jié)構(gòu)的數(shù)據(jù),這是 SQL 語法里不允許的,也是SPL的特色和優(yōu)勢之一。

下圖比較形象地說明了這種結(jié)構(gòu)(長方形表示序表、橢圓形表示記錄、三角形表示關(guān)聯(lián)字段):
淺解比 SQL 更好用的 SPL(二)

A8 直接用SPL中的 group 函數(shù)對這個復(fù)雜結(jié)構(gòu)的序表進(jìn)行分組聚合運(yùn)算,獲得各個雇員曾經(jīng)給出的最小折扣。

再需要注意的一點(diǎn)是 A3 序表被后面兩個不同的動作(A4、A7)都使用了一次,達(dá)到了中間結(jié)果復(fù)用的效果。這種方式對于越是復(fù)雜的計(jì)算,往往作用越大,可以起到類似“數(shù)據(jù)模塊化”的作用。

在 A9 中通過SPL的 join 函數(shù)把 A5(銷售額超過 5000)、A8(最小折扣)兩個序表連接起來;

最后,A10 使用 new 函數(shù)生成新的序表結(jié)構(gòu),而數(shù)據(jù)來自 A9 復(fù)雜結(jié)構(gòu)記錄的不同層次位置。

A10 最終的結(jié)果如下:
淺解比 SQL 更好用的 SPL(二)

簡單回顧一下,對于最后這個比較復(fù)雜的 SQL,如果你是個 SQL 高手,可能會看出第二個子查詢里的 where 并不是必須的,之所以保留它,是因?yàn)橛锌赡軙s小處理數(shù)據(jù)的范圍,從而提升一些性能。這也是 SQL 的另一個特點(diǎn),一方面需要不喘氣的一句話把整個查詢表達(dá)出來,另一方面還需要同時考慮性能優(yōu)化因素,甚至即便考慮到了優(yōu)化方案,也不一定能輕松、自然地描述出來。

在上面的例子中,不難體會出集算器以及SPL對分步過程的重視,每一個步驟的結(jié)果都是可以隨時觀察的,而且前面步驟的結(jié)果也可以重復(fù)利用,同時執(zhí)行步驟也可以被程序員自由定制。這些特點(diǎn)最直接的好處是降低了學(xué)習(xí)和編碼的難度,而更本質(zhì)的是符合人的自然思維,為描述復(fù)雜計(jì)算奠定了基礎(chǔ)。

UNION 等合并兩個集合

SQL 中還有一類針對多個集合(表)的運(yùn)算,就是常說的并、合、交、差(UNION、UNION ALL、INTERSECTION、MINUS),與之對應(yīng)的,在SPL中表示為 &、|、^、\。

集合運(yùn)算時常需要判斷一條記錄是否重復(fù),在這個細(xì)節(jié)上,SQL 和SPL有一點(diǎn)區(qū)別。SPL里因?yàn)樾虮?、記錄,以及字段的值都被看成是一個對象,所以在進(jìn)行并集運(yùn)算時,可以比對元素是否為同一個對象,而 SQL 的記錄是抽象的,不是一個實(shí)體對象,所以只能通過逐個比對兩條記錄的字段值來判斷是否重復(fù)。

我們來看一下實(shí)際的例子:

集算器AB
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=A3B3
5=A3^B3=A3\B3
6>A1.close()

A3 序表的結(jié)果:

淺解比 SQL 更好用的 SPL(二)

B3 序表的結(jié)果:

淺解比 SQL 更好用的 SPL(二)

A3&B3,去掉重復(fù)合并到一起,并集運(yùn)算后得到 A4 序表的結(jié)果:

淺解比 SQL 更好用的 SPL(二)

A3|B3,保留重復(fù)合并到一起,合集運(yùn)算后得到 B4 序表的結(jié)果:

淺解比 SQL 更好用的 SPL(二)

A3^B3,取 A3 和 B3 里相同的記錄,交集運(yùn)算后得到 A5 序表的結(jié)果:

淺解比 SQL 更好用的 SPL(二)

A3\B3,A3 里去掉 B3 中存在的記錄,差集運(yùn)算后得到 A5 序表的結(jié)果:

淺解比 SQL 更好用的 SPL(二)

其它常用語法

最后,再看兩個常用的 SQL 函數(shù)語法,我們來對比看一下SPL的實(shí)現(xiàn)。

CASE WHEN …

SQL 中的 case when … then … else … end,在SPL中用 if 函數(shù),語法是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()

COALESCE(exp1,exp2…expn)

SPL中仍然用 if 函數(shù),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

看完上面這些例子,會給人一個感覺:集算器,或者其中的SPL代碼只是 SQL 的替代品,而常用的關(guān)系數(shù)據(jù)庫系統(tǒng)(RDBMS)本身已經(jīng)是存儲能力(數(shù)據(jù)表)+ 計(jì)算能力 (SQL) 的綜合體了,還要這么一個外來的計(jì)算體系干嘛?

針對這個疑問,有兩個層面的答案。首先是數(shù)據(jù)層面,并非所有要計(jì)算的數(shù)據(jù)都在數(shù)據(jù)庫里。當(dāng)你手邊有個文本、excel 或從一個網(wǎng)絡(luò)服務(wù)臨時得到一些數(shù)據(jù)想要計(jì)算,或者從大量終端采集上來的數(shù)據(jù)馬上要處理出結(jié)果……如果這些都不得不倒騰到數(shù)據(jù)庫里然后再計(jì)算,還真是有點(diǎn)太繞了,更何況還可能涉及到數(shù)據(jù)庫的安裝部署,或者權(quán)限控制等瑣碎而現(xiàn)實(shí)的問題。

其次是計(jì)算層面,對于很多復(fù)雜的計(jì)算過程,SQL 因?yàn)樘焐毕轃o法做到開發(fā)高效、維護(hù)高效、執(zhí)行效高。這也是我們這篇文章最想說明的地方,SQL 的計(jì)算主要還是面向查詢,而這些對“高效”的追求,面向的是更廣泛的數(shù)據(jù)計(jì)算,這正是集算器和SPL語言所要重點(diǎn)改善的。

正因?yàn)橛辛诉@兩個層面的原因,集算器和SPL語言已經(jīng)可以獨(dú)立于各種數(shù)據(jù)存儲形式,在“存儲”和“應(yīng)用”之間,作為一個功能完整、形式靈活、部署方便的“數(shù)據(jù)計(jì)算中間件”而存在。這方面的內(nèi)容,我們會在后面的章節(jié)做更多的介紹和探討。

這里,我們只是先簡單看一下集算器和SPL語言如何基于文本、Excel 等數(shù)據(jù)源進(jìn)行計(jì)算。事實(shí)上,前面這些例子中的計(jì)算步驟完全不用改寫,只需要改變加載數(shù)據(jù)那一句就可以了。也就是把:

=A1.query(“select * from order”)

改為下列任意方式之一:

=file(“d:/data/order.txt”).import@t()// 從文本文件加載數(shù)據(jù)表

=file(“d:/data/orderDetail.xls”).importxls@t()// 從 excel 加載數(shù)據(jù)表

=httpfile(“ http:/ /127.0.0.1/service ”,” param1=value1&param2=value2″) // 從 http server 加載數(shù)據(jù)表

……

很明顯,通過這種簡單明了的數(shù)據(jù)加載方式,可以將各種數(shù)據(jù)源的數(shù)據(jù)形成統(tǒng)一的“序表”,從而在一個計(jì)算過程里可以輕松混合使用。換句話說,不必為了計(jì)算能力而要求必須統(tǒng)一存儲方式。同樣的,在集算器和SPL的環(huán)境中,計(jì)算結(jié)果的存儲,也和加載數(shù)據(jù)一樣方便,也是多樣化的,可以由程序員自由選擇。


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI