轉載自:https://blog.csdn.net/huang_xw/article/details/6402396sql
Oracle的group by除了基本用法之外,還有3種擴展用法,分別是rollup、cube、grouping sets。安全
1 rolluporacle
假設有一個表test,有A、B、C、D、E5列。spa
若是使用group by rollup(A,B,C),首先會對(A、B、C)進行GROUP BY,而後對(A、B)進行GROUP BY,而後是(A)進行GROUP BY,最後對全表進行GROUP BY操做。roll up的意思是「捲起」,這也能夠幫助咱們理解group by rollup就是對選擇的列從右到左以一次少一列的方式進行grouping直到全部列都去掉後的grouping(也就是全表grouping),對於n個參數的rollup,有n+1次的grouping。如下2個sql的結果集是同樣的:.net
Select A,B,C,sum(E) from test group by rollup(A,B,C)blog
與it
Select A,B,C,sum(E) from test group by A,B,Cio
union alltable
Select A,B,null,sum(E) from test group by A,Bclass
union all
Select A,null,null,sum(E) from test group by A
union all
Select null,null,null,sum(E) from test
2 cube
cube的意思是立方,對cube的每一個參數,均可以理解爲取值爲參與grouping和不參與grouping兩個值的一個維度,而後全部維度取值組合的集合就是grouping的集合,對於n個參數的cube,有2^n次的grouping。若是使用group by cube(A,B,C),,則首先會對(A、B、C)進行GROUP BY,而後依次是(A、B),(A、C),(A),(B、C),(B),(C),最後對全表進行GROUP BY操做,一共是2^3=8次grouping。同rollup同樣,也能夠用基本的group by加上結果集的union all寫出一個與group by cube結果集相同的sql:
Select A,B,C,sum(E) from test group by cube(A,B,C);
與
Select A,B,C,sum(E) from test group by A,B,C
union all
Select A,B,null,sum(E) from test group by A,B
union all
Select A,null,C,sum(E) from test group by A,C
union all
Select A,null,null,sum(E) from test group by A
union all
Select null,B,C,sum(E) from test group by B,C
union all
Select null,B,null,sum(E) from test group by B
union all
Select null,null,C,sum(E) from test group by C
union all
Select null,null,null,sum(E) from test;
3 grouping sets
grouping sets就是對參數中的每一個參數作grouping,也就是有幾個參數作幾回grouping,例如使用group by grouping sets(A,B,C),則對(A),(B),(C)進行group by,若是使用group by grouping sets((A,B),C),則對(A,B),(C)進行group by。甚至grouping by grouping set(A,A)都是語法容許的,也就是對(A)進行2次group by,grouping sets的參數容許重複
4 總結
rollup (N+1個分組方案)
cube (2^N個分組方案)
grouping sets (自定義羅列出分組方案)
5 注意點
5.1 機制不一樣
在rollup和cube的說明中分別給出了用基本group by加結果集union all給出告終果集相同的sql,但這只是爲了理解的方便而給出的sql,並不說明rollup和cube與基本group by加結果集union all等價。實際上二者的內部機制是安全不同的,前者除了寫法簡潔之外,運行時不需屢次掃描表,效率遠比後者高。
5.2 集合可運算
3種擴展用法的參數能夠是源表中的某一個具體的列,也能夠是若干列通過計算而造成的一個新列(好比說A+B,A||B),也能夠是這兩種列的一個集合(例如(A+B,C)),對於grouping set更是特殊,能夠是空集合(),表示對全表進行group by。
5.3 group by 與 rollup, cube組合使用
3)Group by的基本用法以及這3種擴展用法能夠組合使用,也就是說能夠出現group by A,rollup(A,B)這樣的用法,oracle將對出如今group by中的每種用法的grouping列集合作笛卡爾積而後對其中的每個元素作group by。這話提及來挺繞口,舉例說明吧,group by A, rollup(A,B),基本用法的grouping集合是(A),rollup(A,B)的grouping集合是((A,B),(A),()),兩個集合的笛卡爾積集合是((A,A,B),(A,A),(A)),因此會首先對(A,A,B)作group by,而後對(A,A)作group by,最後對(A)作group by。實際上對(A,A,B)作group by和對(A,B)作group by二者是徹底等價的(group by A,A,B結果和group by A,B徹底同樣),同理對(A,A)作group by和對(A)作group by也是等價的。簡化後的結果就是首先對(A,B)作group by,而後對(A)作group by,最後再對(A)作group by。下面給出兩個等價的sql以便理解:
Select A,B,sum(E) from test1 group by A, rollup(A,B);
與
Select A,B,sum(E) from test1 group by A,B
Union all
Select A,null,sum(E) from test1 group by A
Union all
Select A,null,sum(E) from test1 group by A;
6 grouping()、grouping_id()、group_id()
6.1 grouping()
參數只有一個,並且必須爲group by中出現的某一列,表示結果集的一行是否對該列作了grouping。對於對該列作了grouping的行而言,grouping()=0,反之爲1;
6.2 grouping_id()
參數能夠是多個,但必須爲group by中出現的列。Grouping_id()的返回值其實就是參數中的每列的grouping()值的二進制向量,例如若是grouping(A)=1,grouping(B)=0,則grouping_id(A,B)的返回值就是二進制的10,轉成10進制就是2。
6.3 group_id()
無參數。見上面的說明3),group by對某些列的集合會進行重複的grouping,而實際上絕大多數狀況下對結果集中的這些重複行是不須要的,那就必須有辦法剔出這些重複grouping的行。當結果集中有n條重複grouping而造成的行時,每行的group_id()分別是0,1,…,n,這樣咱們在條件中加入一個group_id()<1就能夠剔出這些重複grouping的行了。
7 示例
7.1 建表與數據
SQL> create table test(department_id number, a varchar2(20), b varchar2(20));
Table created
SQL> insert into test values(10, 'A', 'B');
1 row inserted
SQL> commit;
Commit complete
7.2 查詢語句
select department_id,
a,
b,
grouping(department_id),
grouping(a),
grouping(b)
from test
group by rollup(department_id, a, b)
order by 4, 5, 6;
select department_id,
a,
b,
grouping(department_id),
grouping(a),
grouping(b)
from test
group by cube(department_id, a, b)
order by 4, 5, 6;