天天看點

Oracle的group by聚合函數擴充cube rollup和grouping setsOracle的group by聚合函數擴充cube rollup和grouping sets

Oracle的group by聚合函數擴充cube rollup和grouping sets

聚合函數是oracle資料倉庫的基礎。為了提高距合的性能,oracle提供了group by條款的擴充。

ü         cube

ü         rollup

ü         grouping

ü         grouping sets

這幾個對sql的擴充使得查詢和報告都變得簡單和迅速。使用者通過使用這幾個擴充功能,可以1,簡化代碼程式設計;2,快速有效的查詢處理;3,減少用戶端和網絡負載。本文以執行個體的方式深入解析這幾種擴充的具體含義和使用環境。

考慮如下關系表。

create table mytest(

subcompany_id varchar2(10),

subcompany_name varchar2(40),

branch_id varchar2(10),

branch_name varchar2(40),

region_id varchar2(10),

region_name varchar2(40),

customer_id varchar2(10),

customer_name varchar2(40),

market_id varchar2(10),

market_name varchar2(49),

sales_count numeric(10,3)

);

comment on table mytest is '測試表';

comment on column mytest.subcompany_id is '分公司編号';

comment on column mytest.subcompany_name is '分公司名稱';

comment on column mytest.branch_id is '經營部編号';

comment on column mytest.branch_name is '經營部名稱';

comment on column mytest.region_id is '片區編号';

comment on column mytest.region_name is '片區名稱';

comment on column mytest.customer_id is '客戶編号';

comment on column mytest.customer_name is '客戶名稱';

comment on column mytest.market_id is '所屬市場級别';

comment on column mytest.market_name is '市場級别名稱';

comment on column mytest.sales_count is '銷售數量';

insert into mytest(subcompany_id,subcompany_name,branch_id,branch_name,region_id,region_name,customer_id,customer_name,market_id,market_name,sales_count)

values('01','分公司1','0101','經營部1','010101','片區1','01010101','客戶1','01','片區1',1);

insert into mytest(subcompany_id,subcompany_name,branch_id,branch_name,region_id,region_name,customer_id,customer_name,market_id,market_name,sales_count)

values('01','分公司1','0101','經營部1','010101','片區1','01010102','客戶2','02','片區2',1);

insert into mytest(subcompany_id,subcompany_name,branch_id,branch_name,region_id,region_name,customer_id,customer_name,market_id,market_name,sales_count)

values('01','分公司1','0101','經營部1','010102','片區2','01010201','客戶1','01','片區1',1);

insert into mytest(subcompany_id,subcompany_name,branch_id,branch_name,region_id,region_name,customer_id,customer_name,market_id,market_name,sales_count)

values('01','分公司1','0101','經營部1','010102','片區2','01010202','客戶2','02','片區2',1);

insert into mytest(subcompany_id,subcompany_name,branch_id,branch_name,region_id,region_name,customer_id,customer_name,market_id,market_name,sales_count)

values('01','分公司1','0102','經營部1','010201','片區1','01020101','客戶1','01','片區1',1);

insert into mytest(subcompany_id,subcompany_name,branch_id,branch_name,region_id,region_name,customer_id,customer_name,market_id,market_name,sales_count)

values('01','分公司1','0102','經營部1','010202','片區2','01020202','客戶2','02','片區2',1);

rollup

rollup的行為非常直接,它根據grouping list的rollup條款建立合計:

首先,它計算grouping條款的标準聚合。

然後,它按照grouping list列從右到左進行更高層的聚合。

最後,建立n+1層的總計。

例如: group by rollup(A,B,C),則oracle最後得到的聚合結果為(A,B,C), (A,B), (A),()

Rollup對group by 的擴充比較簡單,但非常高效,對一個查詢增加的開銷非常少。

考慮如下查詢。

select

subcompany_name,branch_name,region_name,customer_name,

sum

(sales_count)

from

mytest

group by rollup

(subcompany_name,branch_name,region_name,customer_name);

分公司1  經營部1 片區1     客戶1     3  

分公司1  經營部1 片區1     客戶2     2

分公司1  經營部1 片區1            5

分公司1  經營部1 片區2     客戶1     2

分公司1  經營部1 片區2     客戶2     3

分公司1  經營部1 片區2            5

分公司1  經營部1               10

分公司1  經營部2 片區1     客戶1     1

分公司1  經營部2 片區1            1

分公司1  經營部2 片區2     客戶2     1

分公司1  經營部2 片區2            1

分公司1  經營部2               2

分公司1                       12

                      12

上面的查詢傳回如下結果行:

1,  基于subcompany_name,branch_name,region_name,customer_name的聚合。

2,  基于subcompany_name,branch_name,region_name的聚合。

3,  基于subcompany_name,branch_name的聚合。

4,  基于subcompany_name的聚合。

5,  總計

使用者還可以使用rollup包含有限的幾個小計,文法如下:

Group by expr1,rollup(expr2,expr3)這種情況下,group by條款建立2+1層小計。層次為(expr1,expr2,expr3)(expr1,expr2)(expr1)

cube

    Cube進行grouping列規定的grouping,建立所有可能的聚合,例如規定了cube(customer_name,market_name)那麼傳回的結果将是2的2次方個。分别為(customer_name,market_name)(market_name)(customer_name)()

    Cube擴充在計算交叉報表時非常有用,當然我們可以使用select union all替代rollup或cube,但這需要很多的select union all語句。這樣做不僅不夠高效,而且加長了sql語句,不友善維護和擴充。

考慮如下查詢:

select

subcompany_name,branch_name,region_name,

customer_name,market_name,

sum

(sales_count)

from

mytest

group by

subcompany_name,branch_name,region_name,

cube

(customer_name,market_name) ;

分公司1 經營部1 片區1                   5

分公司1 經營部1 片區1            片區1     3

分公司1 經營部1 片區1            片區2     2

分公司1 經營部1 片區1     客戶1            3

分公司1 經營部1 片區1     客戶1     片區1     3

分公司1 經營部1 片區1     客戶2            2

分公司1 經營部1 片區1     客戶2     片區2     2

分公司1 經營部1 片區2                   5

分公司1 經營部1 片區2            片區1     2

分公司1 經營部1 片區2            片區2     3

分公司1 經營部1 片區2     客戶1            2

分公司1 經營部1 片區2     客戶1     片區1     2

分公司1 經營部1 片區2     客戶2            3

分公司1 經營部1 片區2     客戶2     片區2     3

分公司1 經營部2 片區1                   1

分公司1 經營部2 片區1            片區1     1

分公司1 經營部2 片區1     客戶1            1

分公司1 經營部2 片區1     客戶1     片區1     1

分公司1 經營部2 片區2                   1

分公司1 經營部2 片區2            片區2     1

分公司1 經營部2 片區2     客戶2            1

分公司1 經營部2 片區2     客戶2     片區2     1

聯合使用rollup和cube來解決特殊查詢需求

rollup 和cube帶來的一個問題是,在返會的結果中如何能準确區分出那些是小計,哪些是彙總資料呢。這點可以使用grouping和grouping_id函數解決。

另外,我們還可以通過having過慮掉我們不希望在結果中出現的資料。

考慮查詢:給出所有機構的小計,并在此基礎上給出各市場級别的小計。

方案1

使用cube計算所有的結果,然後用having過慮得出符合條件的結果集合。

select grouping

(subcompany_name),

grouping

(branch_name),

grouping

(region_name),

grouping

(customer_name),

grouping

(market_name),

subcompany_name,branch_name,region_name,

customer_name,market_name,

sum

(sales_count)

from

mytest

group by cube

(subcompany_name,branch_name,region_name,customer_name,market_name)

having

(

grouping

(subcompany_name) <=

grouping

(branch_name)

and grouping

(branch_name) <=

grouping

(region_name)

and grouping

(region_name) <=

grouping

(customer_name));

這種方案的缺點在于,首先使用cube計算所有可能的彙總結果需要花費相當長的時間;其次由于結果給出了所有可能的彙總,而我們需要的隻是其中很小一部分,這種情況下使用having過慮結果集也是一件很麻煩的事情。

方案2

使用嵌套查詢,先得出rollup的結果,然後再利用現有結果跟market進行cube的group by計算。

select

subcompany_name,branch_name,region_name,

customer_name,market_name,

sum

(sales_count)

from

(

select

subcompany_name,branch_name,region_name,

customer_name,market_name,

sum

(sales_count) sales_count

from

mytest

group by rollup

(subcompany_name,branch_name,region_name,customer_name) ,market_name

)

group by

subcompany_name,branch_name,region_name,customer_name,

cube

(market_name)

這種方式多執行了一次查詢,代碼長度增加,可讀性也不夠強。另外還要主意過慮掉在裡層查詢中已經彙總的結果。

   方案3

    聯合rollup和cube。

select

subcompany_name,branch_name,region_name,

customer_name,market_name,

sum

(sales_count) sales_count

from

mytest

group by rollup

(subcompany_name,branch_name,region_name,customer_name) ,

cube

(market_name)

order by grouping

(subcompany_name),

grouping

(branch_name),

grouping

(region_name),

grouping

(customer_name),

grouping

(market_name);

grouping sets

grouping sets提供了指定彙總集合條件的功能。例如在上面的查詢中,我們可以通過為select group by語句制定彙總條件()

select

subcompany_name,branch_name,region_name,

customer_name,market_name,

sum

(sales_count) sales_count

from

mytest

group by grouping sets

((subcompany_name,branch_name,region_name,customer_name) ,

                       (subcompany_name,branch_name,region_name) ,

                       (subcompany_name,branch_name) ,

                       (subcompany_name) ,

                       (market_name) ,

                       (subcompany_name,branch_name,region_name,customer_name,market_name) ,

                       (subcompany_name,branch_name,region_name,market_name) ,

                       (subcompany_name,branch_name,market_name) ,

                       (subcompany_name,market_name) ,

                       () )