转载自: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;