溫馨提示×

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

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

跨庫(kù)數(shù)據(jù)表的運(yùn)算

發(fā)布時(shí)間:2020-06-19 11:30:55 來(lái)源:網(wǎng)絡(luò) 閱讀:353 作者:raqsoft 欄目:大數(shù)據(jù)

1.    簡(jiǎn)單合并(FROM)

       所謂跨庫(kù)數(shù)據(jù)表,是指邏輯上同一張數(shù)據(jù)表被分別存儲(chǔ)在不同數(shù)據(jù)庫(kù)中。其原因有可能是因?yàn)閿?shù)據(jù)量太大,放在一個(gè)數(shù)據(jù)庫(kù)難以處理,也可能在業(yè)務(wù)上就需要將生產(chǎn)庫(kù)和歷史庫(kù)分開(kāi)。而不同的數(shù)據(jù)庫(kù),可能只是部署在不同的機(jī)器上的同種數(shù)據(jù)庫(kù),也可能是連類(lèi)型都不同的數(shù)據(jù)庫(kù)系統(tǒng)。

       在面對(duì)跨庫(kù)數(shù)據(jù)表,特別是數(shù)據(jù)庫(kù)類(lèi)型都不相同的情況時(shí),數(shù)據(jù)庫(kù)自帶的工具往往就力所不及了,一般都需要尋找能夠很好地支持多數(shù)據(jù)源類(lèi)型的第三方工具,而集算器,可以說(shuō)是其中的佼佼者了。下面,我們就針對(duì)幾種常見(jiàn)的跨庫(kù)混合運(yùn)算情況詳細(xì)討論一下:

       跨庫(kù)運(yùn)算,簡(jiǎn)單粗暴的思路就是把散布在各個(gè)庫(kù)里的邏輯上相同的數(shù)據(jù)表合并成一個(gè)表,然后在這一個(gè)表上進(jìn)行運(yùn)算。

       例如,在兩個(gè)數(shù)據(jù)庫(kù) HSQL 和 MYSQL 中,分別存儲(chǔ)了一張學(xué)生成績(jī)表,兩者各自保存了一部分學(xué)生信息,如下圖所示:

       跨庫(kù)數(shù)據(jù)表的運(yùn)算

       跨庫(kù)數(shù)據(jù)表的運(yùn)算

       利用集算器,我們可以很容易地將這兩個(gè)結(jié)構(gòu)相同的表合并為一個(gè)表,集算器的 SPL 腳本如下:


A

B

1

=connect("org.hsqldb.jdbcDriver","jdbc:hsqldb:hsql://127.0.0.1/demo?user=sa")

=connect("com.mysql.jdbc.Driver","jdbc:mysql://127.0.0.1:3306/demo?user=root&password=password")

2

=A1.query("select * from 學(xué)生成績(jī)表")

=B1.query("select   * from 學(xué)生成績(jī)表")

3

=A2 | B2

       A1、A2 和 B1、B2 分別讀取了兩個(gè)庫(kù)里的學(xué)生成績(jī)表,而 A3 用一種簡(jiǎn)單直觀的方式就把兩個(gè)表合并了。

       這種方式實(shí)際上是把兩個(gè)表都讀入了內(nèi)存,分別生成了集算器的序表對(duì)象,然后利用序表的運(yùn)算“|”完成了合并。可能有的同學(xué)會(huì)問(wèn):如果我的數(shù)據(jù)量比較大,無(wú)法全部讀入內(nèi)存怎么辦?沒(méi)關(guān)系,專(zhuān)為處理大數(shù)據(jù)而生的集算器,決不會(huì)被這么簡(jiǎn)單的小問(wèn)題難住。我們可以使用游標(biāo),同樣可以實(shí)現(xiàn)表的快速拼接:


A

B

2

=A1.cursor("select * from 學(xué)生成績(jī)表")

=B1.cursor("select   * from 學(xué)生成績(jī)表")

3

=[A2, B2] .conjx()

       A2、B2 分別用游標(biāo)打開(kāi)兩個(gè)庫(kù)里的學(xué)生成績(jī)表,A3 則使用 conjx() 函數(shù)將這兩個(gè)游標(biāo)合并,形成了一個(gè)新的可以同時(shí)訪問(wèn)兩個(gè)表的游標(biāo)。

       對(duì)應(yīng)于 SQL,這種簡(jiǎn)單合并好比只是完成了 from 工作,讓結(jié)構(gòu)相同的跨庫(kù)表的數(shù)據(jù)“縱向”拼接成了一個(gè)可以訪問(wèn)的序表或者游標(biāo),而實(shí)際運(yùn)算中,還會(huì)涉及過(guò)濾 (where/having)、分組聚合 (group+sum/count/avg/max/min)、連接 (join+on)、去重 (distinct)、排序 (order)、取部分?jǐn)?shù)據(jù) (limit+offset),等等操作,下面我們就將對(duì)這些運(yùn)算一一展開(kāi)討論。

       當(dāng)然,我們?cè)谔幚磉@些運(yùn)算的需求時(shí),不能只是簡(jiǎn)單的實(shí)現(xiàn)功能,我們還需要考慮實(shí)現(xiàn)的效率和性能,因此原則上,我們會(huì)盡量利用數(shù)據(jù)庫(kù)的計(jì)算能力,而集算器主要負(fù)責(zé)混合運(yùn)算。不過(guò),有時(shí)也需要由集算器負(fù)責(zé)幾乎所有的運(yùn)算,數(shù)據(jù)庫(kù)僅僅負(fù)責(zé)存儲(chǔ)數(shù)據(jù)。

 

2.    WHERE

       where 過(guò)濾的本質(zhì)是通過(guò)比較計(jì)算,去除比較的結(jié)果是 false 的記錄,因此 where 只作用于一條記錄,不涉及記錄之間的運(yùn)算,也不需要考慮數(shù)據(jù)位于哪個(gè)數(shù)據(jù)庫(kù)。比如,在前面的例子中,我們要統(tǒng)計(jì)出“一班”所有同學(xué)的“數(shù)學(xué)”成績(jī),單庫(kù)中的 SQL 是這樣的:

       SELECT 學(xué)生 ID, 成績(jī) FROM 學(xué)生成績(jī)表 WHERE 科目 =’數(shù)學(xué)’ AND 班級(jí) =‘一班’

       多庫(kù)時(shí),也只要將 where 子句直接寫(xiě)在 SQL 中,讓各個(gè)數(shù)據(jù)庫(kù)去并行處理過(guò)濾就可以了:


A

B

2

=A1.query("select 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表   where 科目 =' 數(shù)學(xué) 'and 班級(jí) =' 一班 ' ")

=B1.query("select   學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'and   班級(jí) =' 一班 ' ")

3

=A2 | B2

       我們也可以讓集算器負(fù)責(zé)所有過(guò)濾運(yùn)算,數(shù)據(jù)庫(kù)僅存儲(chǔ)數(shù)據(jù)。這時(shí)可以使用集算器的 select 函數(shù)(與 SQL 的 select 關(guān)鍵字不同)


A

B

2

=A1.query("select 學(xué)生 ID, 成績(jī), 科目, 班級(jí) from 學(xué)生成績(jī)表")

=B1.query("select   學(xué)生 ID, 成績(jī), 科目, 班級(jí) from 學(xué)生成績(jī)表")

3

=A2.select(科目 =="數(shù)學(xué)" && 班級(jí) =="一班").new(學(xué)生 ID, 成績(jī))

=B2.select(科目 =="數(shù)學(xué)" && 班級(jí) =="一班").new(學(xué)生 ID, 成績(jī))

4

=A3 | B3

       數(shù)據(jù)量較大時(shí),同樣也可以將序表?yè)Q成游標(biāo),使用 conjx 函數(shù)進(jìn)行連接:


A

B

2

=A1.cursor("select 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表   where 科目 =' 數(shù)學(xué) 'and 班級(jí) =' 一班 ' ")

=B1.cursor("select   學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'and   班級(jí) =' 一班 ' ")

3

=[A2, B2].conjx()

 

3.    ORDER BY 和 LIMIT OFFSET

       order by 是在結(jié)果集產(chǎn)生后才進(jìn)行的處理。在上面的例子中,如果我們要按數(shù)學(xué)成績(jī)排序,對(duì)于單數(shù)據(jù)庫(kù),只需要加上 order by 子句:

       SELECT 班級(jí), 學(xué)生 ID, 成績(jī) FROM 學(xué)生成績(jī)表 WHERE 科目 =’數(shù)學(xué)’ AND 班級(jí) =‘一班’ ORDER BY 成績(jī)

       而對(duì)于多數(shù)據(jù)庫(kù),可以讓數(shù)據(jù)庫(kù)先分別排序,然后由集算器歸并有序數(shù)據(jù)。這樣可以最大的發(fā)揮數(shù)據(jù)庫(kù)與并行服務(wù)器的性能。


A

B

2

=A1.query("select 班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表   where 科目 =' 數(shù)學(xué) 'and 班級(jí) =' 一班 'order by 成績(jī)")

=B1.query("select   班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'and 班級(jí) =' 一班 'order by 成績(jī)")

3

=[A2, B2].merge(成績(jī))

       也可以倒序排序,歸并時(shí)在排序字段前加“-”(merge 函數(shù)可以不加“-”,不過(guò)按標(biāo)準(zhǔn)寫(xiě)法是加上的)


A

B

2

=A1.query("select 班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表   where 科目 =' 數(shù)學(xué) 'AND 班級(jí) =' 一班 'order by 成績(jī) desc")

=B1.query("select   班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'AND 班級(jí) =' 一班 'order by 成績(jī) desc")

3

=[A2, B2].merge(- 成績(jī))

       當(dāng)然也可以完全由集算器來(lái)排序:


A

B

2

=A1.query("select 班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'AND   班級(jí) =' 一班 '")

=B1.query("select   班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'AND 班級(jí) =' 一班 '")

3

=[A2.sort( 成績(jī)),   B2.sort(成績(jī))].merge(成績(jī))

       由集算器實(shí)現(xiàn)倒序排序:


A

B

2

=A1.query("select 班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'AND   班級(jí) =' 一班 '")

=B1.query("select   班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'AND 班級(jí) =' 一班 '")

3

=[A2.sort(- 成績(jī)), B2.sort(- 成績(jī))].merge(- 成績(jī))

       而對(duì)于大數(shù)據(jù)量,需要使用游標(biāo)及 mergex 來(lái)完成有序歸并:


A

B

2

=A1.cursor("select 班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'AND   班級(jí) =' 一班 'order by 成績(jī)")

=B1.cursor("select   班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'AND 班級(jí) =' 一班 'order by 成績(jī)")

3

=[A2 , B2].mergex(成績(jī))

       limit 和 offset 的執(zhí)行又在 order 之后,例子中如果想取數(shù)學(xué)成績(jī)除了第一名之后的前十名(可以少于但不能多于),單庫(kù)情況下 SQL 是這樣的:

       SELECT 班級(jí), 學(xué)生 ID, 成績(jī) FROM 學(xué)生成績(jī)表 WHERE 科目 =’數(shù)學(xué)’ AND 班級(jí) =‘一班’ ORDER BY 成績(jī) DESC LIMIT 10 OFFSET 1

       多數(shù)據(jù)庫(kù)時(shí),可以用集算器的 to 函數(shù)實(shí)現(xiàn) limit offset 的功能,to(n+1,n+m) 等同于 limit m offset n


A

B

2

=A1.query("select 班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'AND   班級(jí) =' 一班 'order by 成績(jī) desc")

=B1.query("select   班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'AND 班級(jí) =' 一班 'order by 成績(jī) desc")

3

=[A2, B2].merge(- 成績(jī)).to(2, 11)

       對(duì)于大數(shù)據(jù)量使用游標(biāo)的情況,offset 功能可以使用集算器函數(shù) skip 實(shí)現(xiàn),而 limit 的功能則可以使用函數(shù) fetch 實(shí)現(xiàn)


A

B

2

=A1.cursor("select 班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'AND   班級(jí) =' 一班 'order by 成績(jī) desc")

=B1.cursor("select   班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'AND 班級(jí) =' 一班 'order by 成績(jī) desc")

3

=[A2, B2].mergex(- 成績(jī)).

=A3.skip(1)

4

=A3.fetch(10)


 

4.    聚合運(yùn)算

       我們來(lái)討論五種常見(jiàn)的聚合運(yùn)算:sum/count/avg/max/min。

       ?   sum 的基礎(chǔ)是加法,根據(jù)加法結(jié)合律,各數(shù)據(jù)庫(kù)中內(nèi)部數(shù)據(jù)先分別求和,然后拼接成一張表后再求總和,與先拼接成一張表然后一起求和的結(jié)果,其實(shí)是一樣的。

       ?   count 的本質(zhì),是對(duì)每項(xiàng)非 null 數(shù)據(jù)計(jì) 1,null 數(shù)據(jù)計(jì) 0,然后進(jìn)行累加計(jì)算。所以其本質(zhì)仍是加法運(yùn)算,與 sum 一樣符合加法結(jié)合律。唯一不同的是對(duì)原始數(shù)據(jù)不是累加其本身的數(shù)值而是計(jì) 1(非 null)或計(jì) 0(為 null)。

       ?   avg 的本質(zhì),是當(dāng) count > 0 時(shí) avg = sum/count,當(dāng) count = 0 時(shí) avg = null。顯然 avg 不能像 sum 或 count 那樣先分別計(jì)算了。不過(guò)根據(jù)定義,我們可以先算出 sum 和 count,再通過(guò) sum 和 count 計(jì)算出 avg。

       ?   max 和 min 的基礎(chǔ)都是比較運(yùn)算,而因?yàn)楸容^運(yùn)算具有傳遞性,因此所有數(shù)據(jù)庫(kù)的最值,可以通過(guò)比較各個(gè)數(shù)據(jù)庫(kù)的最值得到。

       依舊是上面的例子,這次我們要求兩個(gè)班全體學(xué)生的數(shù)學(xué)總分、人數(shù)、平均分、最高及最低分,對(duì)于單源數(shù)據(jù):

       SELECT sum(成績(jī)) 總分?jǐn)?shù), count(成績(jī)) 考試人數(shù), avg(成績(jī)) 平均分, max(成績(jī)) 最高分, min(成績(jī)) 最低分 FROM 學(xué)生成績(jī)表 WHERE 科目 ='數(shù)學(xué)'

       聚合運(yùn)算的結(jié)果集很小,只有一行,因此無(wú)論源數(shù)據(jù)量的大小,都可以使用游標(biāo),代碼如下:


A

B

2

=A1.cursor("select sum( 成績(jī)) 總分?jǐn)?shù), count(成績(jī)) 考試人數(shù), max(成績(jī)) 最高分,   min(成績(jī)) 最低分 from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) ' ")

=B1.cursor("select   sum( 成績(jī)) 總分?jǐn)?shù), count(成績(jī)) 考試人數(shù), max(成績(jī)) 最高分, min(成績(jī)) 最低分 from   學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) ' ")

3

=[A2, B2].conjx().total(sum( 總分?jǐn)?shù)), sum(考試人數(shù)), max(最高分), min(最低分))

4

=create(總分?jǐn)?shù), 考試人數(shù), 平均分, 最高分, 最低分).insert(0, A3(1), A3(2), if(A3(2)!=0,A3(1)/A3(2),null), A3(3),   A3(4))

       事實(shí)上,前面提到的 order by +limit offset 本質(zhì)上也可以看成是一種聚合運(yùn)算:top。從這個(gè)角度進(jìn)行優(yōu)化,可以獲得更高的計(jì)算效率。畢竟數(shù)據(jù)量大時(shí),全排序的成本很高,而且取前 N 個(gè)數(shù)據(jù)的操作也并不需要全排序。當(dāng)然,這個(gè)方法對(duì)于數(shù)據(jù)量小的情況也同樣適用。

       具體來(lái)說(shuō),對(duì)于 order by F limit m offset n 的情況,只需先用 top(n+m, F, ~),再用 to(n+1,) 就行了。

       我們?nèi)砸灾暗暮?order by+limit offset 的 SQL 語(yǔ)句為例:

       SELECT 班級(jí), 學(xué)生 ID, 成績(jī) FROM 學(xué)生成績(jī)表 WHERE 科目 =’數(shù)學(xué)’ AND 班級(jí) =‘一班’ ORDER BY 成績(jī) DESC LIMIT 10 OFFSET 1

       對(duì)于多數(shù)據(jù)庫(kù), 腳本如下,其中倒序排序只需在排序字段前加“-”:


A

B

2

=A1.cursor("select 班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'AND   班級(jí) =' 一班 '")

=B1.cursor("select   班級(jí), 學(xué)生 ID, 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'AND 班級(jí) =' 一班 '")

3

=[A2, B2].conjx().top(11, - 成績(jī), ~).to(2,)


 

5.    GROUP BY、DISTINCT 和 HAVING

       A、分組聚合運(yùn)算

       對(duì)于 group by,因?yàn)樽罱K所得結(jié)果與樣本個(gè)體的輸入順序無(wú)關(guān),所以只要樣本的總體不變,最終結(jié)果也不會(huì)變。也就是說(shuō),只要在從分庫(kù)中提取數(shù)據(jù)和最終匯總?cè)繑?shù)據(jù)時(shí),都預(yù)先進(jìn)行了分類(lèi)運(yùn)算即可。

       假設(shè)我們想分別求一、二班的數(shù)學(xué)總分、人數(shù)、平均分、最高及最低分,單數(shù)據(jù)庫(kù)如下:

       SELECT 班級(jí), sum(成績(jī)) 總分?jǐn)?shù), count(成績(jī)) 考試人數(shù), avg(成績(jī)) 平均分, max(成績(jī)) 最高分, min(成績(jī)) 最低分 FROM 學(xué)生成績(jī)表 WHERE 科目 ='數(shù)學(xué)' GROUP BY 班級(jí)

       我們分三種情況討論:

       第一,對(duì)于小數(shù)據(jù),聚合運(yùn)算的結(jié)果集只會(huì)更小,這時(shí)推薦使用 query+groups:


A

B

2

=A1.query("select 班級(jí), sum( 成績(jī)) 總分?jǐn)?shù),   count(成績(jī)) 考試人數(shù), max(成績(jī)) 最高分, min(成績(jī)) 最低分 from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'group by 班級(jí)")

=B1.query("select   班級(jí), sum( 成績(jī)) 總分?jǐn)?shù), count(成績(jī)) 考試人數(shù),   max(成績(jī)) 最高分, min(成績(jī)) 最低分 from 學(xué)生成績(jī)表   where 科目 =' 數(shù)學(xué) 'group by 班級(jí)")

3

=(A2 | B2) .groups(班級(jí): 班級(jí); sum( 總分?jǐn)?shù)): 總分?jǐn)?shù), sum(考試人數(shù)): 考試人數(shù),   max(最高分): 最高分, min(最低分): 最低分 )

4

=A3.new(班級(jí), 總分?jǐn)?shù), 考試人數(shù), if( 考試人數(shù) ==0,   null, 總分?jǐn)?shù) / 考試人數(shù)): 平均分, 最高分, 最低分 )

       第二,對(duì)于大數(shù)據(jù)量,如果結(jié)果集也很大,那么就應(yīng)該使用 cursor+groupx。

       另外,由于大結(jié)果集的分組計(jì)算較慢,需要在外存產(chǎn)生緩存數(shù)據(jù)。而如果我們?cè)跀?shù)據(jù)庫(kù)中對(duì)數(shù)據(jù)先排序,則可以避免這種緩存(此時(shí)計(jì)算壓力會(huì)轉(zhuǎn)到數(shù)據(jù)庫(kù),因此需要根據(jù)實(shí)際情況權(quán)衡,通常情況下,數(shù)據(jù)庫(kù)服務(wù)器的計(jì)算能力會(huì)更強(qiáng)一些)。

       具體的辦法是對(duì) SQL 的結(jié)果集使用 order by 排序,然后在集算器中使用 mergex 函數(shù)歸并后,再使用 groupx 的 @o 選項(xiàng)分組:


A

B

2

=A1.cursor("select   班級(jí), sum( 成績(jī)) 總分?jǐn)?shù), count(成績(jī)) 考試人數(shù),   max(成績(jī)) 最高分, min(成績(jī)) 最低分 from 學(xué)生成績(jī)表   where 科目 =' 數(shù)學(xué) 'group by 班級(jí)   order by 班級(jí)")

=B1.cursor("select 班級(jí), sum( 成績(jī)) 總分?jǐn)?shù),   count(成績(jī)) 考試人數(shù), max(成績(jī)) 最高分, min(成績(jī)) 最低分 from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'group by 班級(jí) order   by 班級(jí)")

3

=[A2   , B2].mergex(班級(jí)).groupx@o(班級(jí): 班級(jí); sum( 總分?jǐn)?shù)): 總分?jǐn)?shù),   sum(考試人數(shù)): 考試人數(shù), max(最高分): 最高分, min(最低分): 最低分 )

4

=A3.new(班級(jí), 總分?jǐn)?shù), 考試人數(shù), if( 考試人數(shù) ==0, null, 總分?jǐn)?shù) / 考試人數(shù)): 平均分, 最高分, 最低分 )

       當(dāng)然如果不希望加重?cái)?shù)據(jù)庫(kù)負(fù)擔(dān),也可以讓數(shù)據(jù)庫(kù)只做分組而不排序,此時(shí)集算器直接用 groupx,注意不能加 @o 選項(xiàng)。另×××總數(shù)據(jù)時(shí),也要把 mergex 換成 conjx:


A

B

2

=A1.cursor("select 班級(jí), sum( 成績(jī)) 總分?jǐn)?shù),   count(成績(jī)) 考試人數(shù), max(成績(jī)) 最高分, min(成績(jī)) 最低分 from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'group by 班級(jí)")

=B1.cursor("select   班級(jí), sum( 成績(jī)) 總分?jǐn)?shù), count(成績(jī)) 考試人數(shù),   max(成績(jī)) 最高分, min(成績(jī)) 最低分 from 學(xué)生成績(jī)表   where 科目 =' 數(shù)學(xué) 'group by 班級(jí)")

3

=[A2, B2].conjx().groupx( 班級(jí): 班級(jí); sum( 總分?jǐn)?shù)): 總分?jǐn)?shù), sum(考試人數(shù)): 考試人數(shù),   max(最高分): 最高分, min(最低分): 最低分 )

4

=A3.new(班級(jí), 總分?jǐn)?shù), 考試人數(shù), if( 考試人數(shù) ==0,   null, 總分?jǐn)?shù) / 考試人數(shù)): 平均分, 最高分, 最低分 )

       第三,如果已明確地知道結(jié)果集很小,那么推薦用 cursor+groups

       此時(shí) groups 比 groupx 有更好的性能,因?yàn)?groups 將運(yùn)算數(shù)據(jù)都保存在內(nèi)存中,比 groupx 節(jié)省了寫(xiě)入外存文件的時(shí)間。

       另外用 groups 可以不要求在數(shù)據(jù)庫(kù)中預(yù)先排序,因?yàn)閿?shù)據(jù)庫(kù) group by 的結(jié)果集本身不一定有序,再使用 orde by 排序也會(huì)增加成本。而對(duì)于小結(jié)果集,集算器用 groups@o 也并不一定比直接用 groups 更有效率。

       通常,匯總數(shù)據(jù)要用 conjx


A

B

2

=A1.cursor("select 班級(jí), sum( 成績(jī)) 總分?jǐn)?shù),   count(成績(jī)) 考試人數(shù), max(成績(jī)) 最高分, min(成績(jī)) 最低分 from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) 'group by 班級(jí)")

=B1.cursor("select   班級(jí), sum( 成績(jī)) 總分?jǐn)?shù), count(成績(jī)) 考試人數(shù),   max(成績(jī)) 最高分, min(成績(jī)) 最低分 from 學(xué)生成績(jī)表   where 科目 =' 數(shù)學(xué) 'group by 班級(jí)")

3

=[A2, B2].conjx().groups( 班級(jí): 班級(jí); sum( 總分?jǐn)?shù)): 總分?jǐn)?shù), sum(考試人數(shù)): 考試人數(shù),   max(最高分): 最高分, min(最低分): 最低分 )

4

=A3.new(班級(jí), 總分?jǐn)?shù), 考試人數(shù), if( 考試人數(shù) ==0,   null, 總分?jǐn)?shù) / 考試人數(shù)): 平均分, 最高分, 最低分 )

       B、去重后計(jì)數(shù) (count distinct)

       在各個(gè)數(shù)據(jù)庫(kù)內(nèi)去重,可以使用 distinct 關(guān)鍵字。而數(shù)據(jù)庫(kù)之間的數(shù)據(jù)去重,則可以使用集算器的 merge@u 函數(shù)。要注意的是使用前應(yīng)該確保表內(nèi)數(shù)據(jù)對(duì)主鍵字段(或者具有唯一性的一個(gè)或多個(gè)字段)有序。

       對(duì)于 distinct 來(lái)說(shuō), sum(distinct)、avg(distinct) 的計(jì)算方法與 count(distinct) 大同小異,而且業(yè)務(wù)中不常用到,而 max(distinct)、min(distinct) 與單純使用 max、min 沒(méi)有區(qū)別。因此,我們只以 count(distinct) 為例加以說(shuō)明。

       比如,想要計(jì)算全年級(jí)(假設(shè)只有一班和二班)語(yǔ)數(shù)外三科至少有一科不及格需要補(bǔ)考的總?cè)藬?shù),單數(shù)據(jù)庫(kù)的 SQL 是這樣的:

       SELECT count(distinct 學(xué)生 ID) 人數(shù) FROM 學(xué)生成績(jī)表 WHERE 成績(jī) <60

       對(duì)于多源數(shù)據(jù),全分組聚合在使用游標(biāo)或序表方面沒(méi)有差別,為了語(yǔ)法簡(jiǎn)便起見(jiàn)以游標(biāo)為例:


A

B

2

=A1.cursor("select distinct 班級(jí), 學(xué)生 ID from 學(xué)生成績(jī)表   where 成績(jī) <60 order by 班級(jí), 學(xué)生 ID")

=B1.cursor("select   distinct 班級(jí), 學(xué)生 ID from 學(xué)生成績(jī)表 where 成績(jī) <60 order by 班級(jí), 學(xué)生 ID")

3

=[A2, B2].mergex@u(班級(jí), 學(xué)生 ID).total(count( 學(xué)生 ID))

       再如,想要分別計(jì)算每班語(yǔ)數(shù)外三科至少有一科不及格需要補(bǔ)考的總?cè)藬?shù),單數(shù)據(jù)庫(kù)的 SQL 是這樣的:

       SELECT 班級(jí), count(distinct 學(xué)生 ID) 人數(shù) FROM 學(xué)生成績(jī)表 WHERE 成績(jī) <60 GROUP BY 班級(jí)

       對(duì)于多數(shù)據(jù)庫(kù),同樣需要先匯總?cè)ブ?,再進(jìn)行分組聚合。匯總前需要數(shù)據(jù)有序,且匯總后數(shù)據(jù)仍然有序,所以分組函數(shù) groups 和 groupx 都可以使用 @o 選項(xiàng)。

       對(duì)于小數(shù)據(jù)量,可以使用 merge@u、groups@o 和 query:


A

B

2

=A1.query("select distinct 班級(jí), 學(xué)生 ID from 學(xué)生成績(jī)表   where 成績(jī) <60 order by 班級(jí), 學(xué)生 ID")

=B1.query("select   distinct 班級(jí), 學(xué)生 ID from 學(xué)生成績(jī)表 where 成績(jī) <60 order by 班級(jí), 學(xué)生 ID")

3

=[A2, B2].merge@u(班級(jí), 學(xué)生 ID) .groups@o(班級(jí): 班級(jí); count( 學(xué)生 ID): 補(bǔ)習(xí)人數(shù) )

       對(duì)于大數(shù)據(jù)量小結(jié)果集,可以使用 mergex@u、groups@o 和 cursor:


A

B

2

=A1.cursor("select distinct 班級(jí), 學(xué)生 ID from 學(xué)生成績(jī)表   where 成績(jī) <60 order by 班級(jí), 學(xué)生 ID")

=B1.cursor("select   distinct 班級(jí), 學(xué)生 ID from 學(xué)生成績(jī)表 where 成績(jī) <60 order by 班級(jí), 學(xué)生 ID")

3

=[A2, B2].mergex@u(班級(jí), 學(xué)生 ID) .groups@o(班級(jí): 班級(jí); count( 學(xué)生 ID): 補(bǔ)習(xí)人數(shù) )

       對(duì)于大數(shù)據(jù)量大結(jié)果集,可以使用 mergex@u、groupx@o 和 cursor:


A

B

2

=A1.cursor("select distinct 班級(jí), 學(xué)生 ID from 學(xué)生成績(jī)表   where 成績(jī) <60 order by 班級(jí), 學(xué)生 ID")

=B1.cursor("select   distinct 班級(jí), 學(xué)生 ID from 學(xué)生成績(jī)表 where 成績(jī) <60 order by 班級(jí), 學(xué)生 ID")

3

=[A2, B2].mergex@u(班級(jí), 學(xué)生 ID) .groupx@o(班級(jí): 班級(jí); count( 學(xué)生 ID): 補(bǔ)習(xí)人數(shù) )

       C、對(duì)聚合字段過(guò)濾(having)

       having 是對(duì)聚合 (分組) 后得出的結(jié)果集再做過(guò)濾。所以當(dāng)語(yǔ)句中有 having 出現(xiàn)時(shí),如果聚合 (分組) 操作沒(méi)有徹底執(zhí)行完畢,需要將 having 子句先提取出來(lái)。待數(shù)據(jù)徹底完成聚合 (分組) 操作之后,再執(zhí)行條件過(guò)濾。

       對(duì)于多源數(shù)據(jù),如果聚合計(jì)算是在匯總之后才能最終完成,那么 having 必須使用集算器的函數(shù) select 來(lái)實(shí)現(xiàn)過(guò)濾。

       下面主要說(shuō)明這種聚合計(jì)算在匯總之后才完成的情況:比如,想要獲得一班和二班的三個(gè)科目的考試中,有哪些平均分是低于 60 分的。對(duì)于單數(shù)據(jù)庫(kù),SQL 可以這樣寫(xiě):

SELECT 班級(jí), 科目, avg(成績(jī)) 平均分 FROM 學(xué)生成績(jī)表 GROUP BY 班級(jí), 科目 HAVING avg(成績(jī))<60

       對(duì)于多數(shù)據(jù)庫(kù),相關(guān)集算器執(zhí)行代碼如下:


A

B

2

=A1.query("select 班級(jí), 科目, sum( 成績(jī)) 總分, count(成績(jī)) 人數(shù)   from 學(xué)生成績(jī)表 group by 班級(jí), 科目")

=B1.query("select   班級(jí), 科目, sum( 成績(jī)) 總分, count(成績(jī)) 人數(shù) from 學(xué)生成績(jī)表 group by 班級(jí), 科目")

3

=(A2 | B2).groups(班級(jí): 班級(jí), 科目: 科目; sum( 總分): 總分, sum(人數(shù)): 人數(shù) ).new( 班級(jí), 科目, ( 總分 / 人數(shù)): 平均分 )

4

=A3.select(平均分 <60)

       對(duì)于大數(shù)據(jù)量,需要使用游標(biāo) (select 函數(shù)同樣適用于游標(biāo))


A

B

2

=A1.cursor("select 班級(jí), 科目, sum( 成績(jī)) 總分, count(成績(jī)) 人數(shù)   from 學(xué)生成績(jī)表 group by 班級(jí), 科目 order by 班級(jí), 科目")

=B1.cursor("select   班級(jí), 科目, sum( 成績(jī)) 總分, count(成績(jī)) 人數(shù) from 學(xué)生成績(jī)表 group by 班級(jí), 科目 order by 班級(jí), 科目")

3

=[A2, B2].mergex(班級(jí), 科目).groupx@o(班級(jí): 班級(jí), 科目: 科目; sum( 總分): 總分, sum(人數(shù)): 人數(shù) ).new( 班級(jí), 科目, ( 總分 / 人數(shù)): 平均分 )

4

=A3.select(平均分 <60)

 

6.    JOIN ON

       跨庫(kù)的 JOIN 實(shí)現(xiàn)起來(lái)非常困難,不過(guò)比較幸運(yùn)的是,我們可以通過(guò)存儲(chǔ)設(shè)計(jì)避免很多跨庫(kù) JOIN。我們分三種情況討論:

       1. 同維表分庫(kù),需要重新拼接為一個(gè)表

       2. 要連接的外鍵表在每個(gè)庫(kù)中都有相同的一份

       3. 需要連接的外鍵表在另一個(gè)庫(kù)中

       對(duì)于集算器來(lái)講,前兩種的處理情況是一樣的:都不需要涉及跨庫(kù) join,join 操作都可以在數(shù)據(jù)庫(kù)內(nèi)完成。區(qū)別只在于第一種是分庫(kù)表,數(shù)據(jù)庫(kù)之間沒(méi)有重復(fù)數(shù)據(jù);而第二種則要求把外鍵表的數(shù)據(jù)復(fù)制到每個(gè)庫(kù)中。

       如果外鍵表沒(méi)有復(fù)制到每個(gè)庫(kù)中,那就會(huì)涉及真正的跨庫(kù) join,因?yàn)楹軓?fù)雜,這里只舉一個(gè)內(nèi)存外鍵表的例子,其它更復(fù)雜情況會(huì)有專(zhuān)門(mén)的文章闡述。

       A、同維表或主子表同步分庫(kù)

       所謂同維表,簡(jiǎn)單來(lái)講就是兩個(gè)表的主鍵字段完全一樣,且其中一個(gè)表的主鍵與另一個(gè)表的主鍵有邏輯意義上的外鍵約束(并不要求數(shù)據(jù)庫(kù)中一定有真正的外鍵,主鍵同理也是邏輯上的主鍵并不一定存在于數(shù)據(jù)庫(kù)中)。

       假設(shè)有兩個(gè)庫(kù),每個(gè)庫(kù)中有兩個(gè)表,分別記為 A 庫(kù)中的 A1 表和 A2 表,B 庫(kù)中的 B1 表和 B2 表。從邏輯上看 1 表是 A1 表加上 B1 表,2 表是 A2 表加上 B2 表,我們?cè)偌僭O(shè) 1 表與 2 表為同維表,現(xiàn)在要做 1 表與 2 表的 join 連接運(yùn)算。

       所謂同步分庫(kù),就是在設(shè)計(jì)分庫(kù)存儲(chǔ)時(shí),保證了 1 表和 2 表按主鍵進(jìn)行了同步的分割。也就是必須保證分庫(kù)之后,A1 和 B2 的 join 等值連接的結(jié)果是空集,同樣 A2 和 B1 的 join 等值連接的結(jié)果也是空集,這樣也就不必有跨庫(kù)的 join 連接運(yùn)算了。

       舉例說(shuō)明,比如有兩張表:股票信息與公司信息,表的結(jié)構(gòu)如下:

       公司信息

       跨庫(kù)數(shù)據(jù)表的運(yùn)算

       股票信息

       跨庫(kù)數(shù)據(jù)表的運(yùn)算

       兩個(gè)表的主鍵都是 (公司代碼, 股票代碼),且股票信息的主鍵與公司信息的主鍵有邏輯意義上的外鍵約束關(guān)系,二者互為同維表。

       現(xiàn)在假設(shè)我想將兩個(gè)表拼接在一起,單數(shù)據(jù)庫(kù)時(shí) SQL 是這樣的:

       SELECT * FROM 公司信息 T1 JOIN 股票信息 T2 ON T1. 公司代碼 =T2. 公司代碼 AND T1. 股票代碼 = T2. 股票代碼

       現(xiàn)假設(shè)公司信息分為兩部分,分別存于 HSQL 和 MYSQL 數(shù)據(jù)庫(kù)中,股票信息同樣分為兩部分,分別存于 HSQL 和 MYSQL 數(shù)據(jù)庫(kù)中,且二者是同步分庫(kù)。

       join 連接公司信息與股票信息的集算器代碼:


A

B

2

=A1.query("SELECT * FROM 公司信息 T1 JOIN 股票信息 T2 ON T1. 公司代碼 =T2. 公司代碼 AND T1. 股票代碼 = T2. 股票代碼")

=B1.query("SELECT * FROM 公司信息 T1 JOIN 股票信息 T2 ON T1. 公司代碼 =T2. 公司代碼 AND T1. 股票代碼 = T2. 股票代碼")

3

=A2 | B2

       對(duì)于大數(shù)據(jù):


A

B

2

=A1.cursor("SELECT * FROM 公司信息 T1 JOIN 股票信息 T2 ON T1. 公司代碼 =T2. 公司代碼 AND T1. 股票代碼 = T2. 股票代碼")

=B1.cursor("SELECT * FROM 公司信息 T1 JOIN 股票信息 T2 ON T1. 公司代碼 =T2. 公司代碼 AND T1. 股票代碼 = T2. 股票代碼")

3

=[A2,   B2].conjx()

       主子表的情況與同維表類(lèi)似,即一個(gè)表(主表)的主鍵字段被另一個(gè)表(子表)的主鍵字段所包含,且子表中對(duì)應(yīng)的主鍵字段與主表的主鍵有邏輯意義上的外鍵約束關(guān)系。

       舉例說(shuō)明,比如有兩張表:訂單與訂單明細(xì),表的結(jié)構(gòu)如下:

       訂單

       跨庫(kù)數(shù)據(jù)表的運(yùn)算

       訂單明細(xì)

       跨庫(kù)數(shù)據(jù)表的運(yùn)算

       其中訂單是主表,主鍵為 (訂單 ID);而訂單明細(xì)為子表,主鍵為 (訂單 ID, 產(chǎn)品 ID),且訂單明細(xì)的主鍵字段訂單 ID,與訂單的主鍵有邏輯意義上的外鍵約束關(guān)系,顯然二者為主子表的關(guān)系。

       現(xiàn)在假設(shè)我想將兩個(gè)表拼接在一起,單數(shù)據(jù)庫(kù)的 SQL 是這樣的:

       SELECT * FROM 訂單 T1 JOIN 訂單明細(xì) T2 ON T1. 訂單 ID=T2. 訂單 ID

       現(xiàn)假設(shè)訂單分為兩部分,分別存于 HSQL 和 MYSQL 數(shù)據(jù)庫(kù)中,訂單明細(xì)同樣分為兩部分,分別存于 HSQL 和 MYSQL 數(shù)據(jù)庫(kù)中,且二者同步分庫(kù)。

       join 連接訂單與訂單明細(xì)的集算器代碼:


A

B

2

=A1.query("SELECT * FROM 訂單 T1 JOIN 訂單明細(xì) T2 ON T1. 訂單 ID=T2. 訂單 ID")

=B1.query("SELECT * FROM 訂單 T1 JOIN 訂單明細(xì) T2 ON T1. 訂單 ID=T2. 訂單 ID")

3

=A2 | B2

       對(duì)于大數(shù)據(jù):


A

B

2

=A1.cursor("SELECT * FROM 訂單 T1 JOIN 訂單明細(xì) T2 ON T1. 訂單 ID=T2. 訂單 ID")

=B1.cursor("SELECT * FROM 訂單 T1 JOIN 訂單明細(xì) T2 ON T1. 訂單 ID=T2. 訂單 ID")

3

=[A2,   B2].conjx()

       B、外鍵表復(fù)制進(jìn)每個(gè)庫(kù)

       所謂外鍵表,即是指連接字段為外鍵字段的情況。這種外鍵表 join 也是業(yè)務(wù)上常見(jiàn)的一種情況。因?yàn)橐B接的外鍵表在每個(gè)庫(kù)中都有同一份,那么兩個(gè)外鍵表匯總并去重后,其實(shí)還是任一數(shù)據(jù)庫(kù)中原來(lái)就有的那個(gè)外鍵表。

       而 join 的連接操作,本質(zhì)上可以視為一種乘法,因?yàn)?join 連接等價(jià)于 cross join 后再用 on 中條件進(jìn)行過(guò)濾。則根據(jù)乘法分配率可以推導(dǎo)出:若是需要做連接操作的外鍵表(不妨設(shè)為連接右側(cè)的表)在每個(gè)庫(kù)中都有同一份,則連接左側(cè)的表(每個(gè)數(shù)據(jù)庫(kù)中各有其一部分)在匯總后再連接,等同于各數(shù)據(jù)中的連接左側(cè)的表與外鍵表先做連接操作后,再匯總到一起的結(jié)果。如圖所示:

       跨庫(kù)數(shù)據(jù)表的運(yùn)算

       所以我們?cè)诖鎯?chǔ)設(shè)計(jì)時(shí),只要在每個(gè)數(shù)據(jù)庫(kù)中把外鍵表都重復(fù)一下,就可以避免復(fù)雜的跨庫(kù) join 操作。一般情況下,外鍵表作為維表的數(shù)據(jù)量相對(duì)較小,這樣重復(fù)的成本就不會(huì)很高,而事實(shí)表則會(huì)得很大,然后用分庫(kù)存儲(chǔ)的方法,來(lái)解決運(yùn)算速度緩慢或存儲(chǔ)空間不足等問(wèn)題。

       例如,有兩個(gè)表:客戶銷(xiāo)售表和客戶表,其中客戶銷(xiāo)售表的外鍵字段:客戶,與客戶表的主鍵字段:客戶 ID,有外鍵約束關(guān)系?,F(xiàn)在我們想查詢面向河北省各公司的銷(xiāo)售額記錄,對(duì)于單數(shù)據(jù)源,它的 SQL 是這樣寫(xiě)的:

       SELECT T1. 公司名稱(chēng) 公司名稱(chēng), T2. 訂購(gòu)日期 訂購(gòu)日期, T2. 銷(xiāo)售額 銷(xiāo)售額 FROM 客戶表 T1 JOIN 客戶銷(xiāo)售表 T2 ON T1. 客戶 ID=T2. 客戶 WHERE T1. 省份 ='河北'

       對(duì)于多數(shù)據(jù)源的情況,我們假設(shè)客戶銷(xiāo)售表分別存儲(chǔ)在兩個(gè)不同的數(shù)據(jù)庫(kù)中,而每個(gè)數(shù)據(jù)庫(kù)中都有同一份的客戶表做為外鍵表。則相關(guān)的集算器代碼如下:


A

B

2

=A1.query("select T1. 公司名稱(chēng) 公司名稱(chēng), T2. 訂購(gòu)日期 訂購(gòu)日期, T2. 銷(xiāo)售額 銷(xiāo)售額 from 客戶表 T1 join 客戶銷(xiāo)售表 T2 on T1. 客戶 ID=T2. 客戶 where T1. 省份 =' 河北 ' ")

=B1.query("select   T1. 公司名稱(chēng) 公司名稱(chēng), T2. 訂購(gòu)日期 訂購(gòu)日期,   T2. 銷(xiāo)售額 銷(xiāo)售額 from 客戶表 T1 join 客戶銷(xiāo)售表 T2 on T1. 客戶 ID=T2. 客戶 where T1. 省份 =' 河北 ' ")

3

=A2 | B2

       大數(shù)據(jù)量使用游標(biāo)時(shí):


A

B

2

=A1.cursor("select T1. 公司名稱(chēng) 公司名稱(chēng), T2. 訂購(gòu)日期 訂購(gòu)日期, T2. 銷(xiāo)售額 銷(xiāo)售額 from 客戶表 T1 join 客戶銷(xiāo)售表 T2 on T1. 客戶 ID=T2. 客戶 where T1. 省份 =' 河北 ' ")

=B1.cursor("select   T1. 公司名稱(chēng) 公司名稱(chēng), T2. 訂購(gòu)日期 訂購(gòu)日期,   T2. 銷(xiāo)售額 銷(xiāo)售額 from 客戶表 T1 join 客戶銷(xiāo)售表 T2 on T1. 客戶 ID=T2. 客戶 where T1. 省份 =' 河北 ' ")

3

=[A2, B2].conjx()

       C、需要連接的外鍵表在另一個(gè)庫(kù)中

       對(duì)于維表(外鍵表)也被分庫(kù)的情況,我們只考慮維表全部可內(nèi)存化的情況,不可內(nèi)存化時(shí),常常就不適合再將數(shù)據(jù)存在數(shù)據(jù)庫(kù)中了,需要專(zhuān)門(mén)針對(duì)性的的存儲(chǔ)和計(jì)算方案,這將在另外的文章中專(zhuān)門(mén)討論。在這里我們只通過(guò)例子來(lái)討論維表可內(nèi)存化的情況。

       對(duì)于這種情況,當(dāng)涉及的數(shù)據(jù)量比較大而需要使用游標(biāo)時(shí),計(jì)算邏輯會(huì)變得比較復(fù)雜。所以我們?cè)谶@里只講一下針對(duì)小數(shù)據(jù)量的使用序表的 join 處理方法。關(guān)于對(duì)大數(shù)據(jù)量的使用游標(biāo)的 join 處理,會(huì)另有一篇文章做專(zhuān)門(mén)的介紹。

       當(dāng)要做 join 連接運(yùn)算的外鍵表全部或部分存儲(chǔ)在另一個(gè)庫(kù)中時(shí),最直觀的辦法就是將兩個(gè)表都提取出來(lái)并各自匯總后,再計(jì)算 join 連接。

       下面仍以客戶銷(xiāo)售表和客戶表來(lái)舉例,假設(shè)外鍵表客戶表也分別存儲(chǔ)在兩個(gè)數(shù)據(jù)庫(kù)中,此時(shí)就不能在 SQL 中使用 join 關(guān)鍵字來(lái)實(shí)現(xiàn)連接運(yùn)算了,但我們可以將其提取出來(lái)后,用集算器的 join 函數(shù)來(lái)實(shí)現(xiàn)目的,它的集算器代碼如下所示:


A

B

2

=A1.query("select 客戶 ID 客戶, 公司名稱(chēng) from 客戶表   where 省份 =' 河北 ' ")

=B1.query("select   客戶 ID 客戶, 公司名稱(chēng) from 客戶表 where 省份 =' 河北 ' ")

3

=A2 | B2

4

=A1.query("select 客戶, 訂購(gòu)日期, 銷(xiāo)售額 from 客戶銷(xiāo)售表")

=B1.query("select 客戶, 訂購(gòu)日期, 銷(xiāo)售額 from 客戶銷(xiāo)售表")

5

=A4 | B4

6

=join(A3: 客戶表, 客戶; A5: 客戶銷(xiāo)售表, 客戶)

7

=A4.new(~.field(1).field(1): 客戶, ~.field(1).field(2): 公司名稱(chēng), ~.field(2).field(2): 訂購(gòu)日期,   ~.field(2).field(3): 銷(xiāo)售額 )

       當(dāng)事實(shí)表數(shù)據(jù)量較大的時(shí)候,也可以使用游標(biāo)處理事實(shí)表,只需將 join 換成 cs.join 即可:


A

B

2

=A1.query("select 客戶 ID 客戶, 公司名稱(chēng) from 客戶表   where 省份 =' 河北 ' ")

=B1.query("select   客戶 ID 客戶, 公司名稱(chēng) from 客戶表 where 省份 =' 河北 ' ")

3

=A2 | B2

4

=A1.cursor("select 客戶, 訂購(gòu)日期, 銷(xiāo)售額 from 客戶銷(xiāo)售表")

=B1.cursor("select 客戶, 訂購(gòu)日期, 銷(xiāo)售額 from 客戶銷(xiāo)售表")

5

=[A4, B4].conjx()

6

=A5.join(客戶, A3: 客戶)

 

7.    簡(jiǎn)單 SQL

       前面我們主要是從計(jì)算原理的角度出發(fā),分析了如何使用集算器實(shí)現(xiàn)類(lèi)似 SQL 效果的多數(shù)據(jù)源混合計(jì)算。除此之外,集算器還提供了一種更簡(jiǎn)單、直觀的方法,那就是可以在各個(gè)數(shù)據(jù)庫(kù)上通過(guò) SQL 查詢獲取游標(biāo),用所有這些游標(biāo)構(gòu)建成一個(gè)多路游標(biāo)對(duì)象,再用簡(jiǎn)單 SQL 對(duì)這個(gè)多路游標(biāo)做二次處理。如果簡(jiǎn)單 SQL 中沒(méi)有涉及 join 的運(yùn)算,甚至還可以讓集算器直接將一句簡(jiǎn)單 SQL 翻譯成各種數(shù)據(jù)庫(kù)的 SQL,從而實(shí)現(xiàn)更進(jìn)一步的自動(dòng)化。不過(guò)這種辦法屬于比較保守的做法,雖然簡(jiǎn)單直接,但不能利用所了解的數(shù)據(jù)情況進(jìn)行優(yōu)化(比如不會(huì)使用 groups),因此性能就會(huì)差一些。

       下面仍舊用學(xué)生成績(jī)的例子,我們想要計(jì)算每個(gè)班的數(shù)學(xué)成績(jī)的總分、考試人數(shù)、平均分、最高分和最低分,使用簡(jiǎn)單 SQL 處理這個(gè)問(wèn)題的集算器代碼如下:


A

B

2

=A1.cursor("select 班級(jí), 成績(jī) from 學(xué)生成績(jī)表   where 科目 =' 數(shù)學(xué) ' ")

=B1.cursor("select   班級(jí), 成績(jī) from 學(xué)生成績(jī)表 where 科目 =' 數(shù)學(xué) ' ")

3

=[A2, B2].mcursor()

4

=connect().query("select 班級(jí), sum( 成績(jī)) 總分,   count(成績(jī)) 考生人數(shù), avg(成績(jī)) 平均分, max(成績(jī)) 最高分, min(成績(jī)) 最低分 from   {A3} group by 班級(jí)")

       因?yàn)槭褂昧擞螛?biāo),所以這種寫(xiě)法也可以用于大數(shù)據(jù)量。另外再提一句,這個(gè)辦法甚至也可以用于非數(shù)據(jù)庫(kù)的數(shù)據(jù)源(比如文件數(shù)據(jù)源)!簡(jiǎn)單 SQL 的特性可參考相關(guān)文檔,這里就不再進(jìn)一步舉例了。

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

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

AI