[转]详解Oracle高级分组函数(ROLLUP, CUBE, GROUPING SETS)


 

 

原文地址:http://blog.csdn.net/u014558001/article/details/42387929

本文主要讲解 ROLLUP, CUBE, GROUPING SETS的主要用法,这些函数可以理解为GroupBy分组函数封装后的精简用法,相当于多个union all 的组合显示效果,但是要比 多个union all的效率要高。

其实这些函数在时间的程序开发中应用的并不多,至少在我工作的多年时间中没用过几次,因为现在的各种开发工具/平台都自带了这些高级分组统计功能,使用的方便性及美观性都比这些要好。但如果临时查下数据,用这些函数还是不错的。

view plain copy
  1. createtable EMP2  
  2. (  
  3.   ID       NUMBER,  -- 员工编号  
  4.   NAME     VARCHAR2(20), --姓名  
  5.   SEX     VARCHAR2(2),  --性别  
  6.   HIREDATE DATE,         --入职日期  
  7.   BASE    VARCHAR2(20), --工作母地  
  8.   DEPT    VARCHAR2(20), --所在部门  
  9.   SAL     NUMBER        --月工资  
  10. );  

 

2.      插入测试数据

 

[sql] view plain copy
  1. insert into emp2 (ID, NAME, SEX, HIREDATE,BASE, DEPT, SAL)  
  2. values (107, '小月', '女', to_date('01-09-2013', 'dd-mm-yyyy'), '北京','营运', 9000);  
  3. insert into emp2 (ID, NAME, SEX, HIREDATE,BASE, DEPT, SAL)  
  4. values (108, '小美', '女', to_date('01-06-2011', 'dd-mm-yyyy'), '上海','营运', 11000);  
  5. insert into emp2 (ID, NAME, SEX, HIREDATE,BASE, DEPT, SAL)  
  6. values (101, '张三', '男', to_date('01-01-2011', 'dd-mm-yyyy'), '北京','财务', 8000);  
  7. insert into emp2 (ID, NAME, SEX, HIREDATE,BASE, DEPT, SAL)  
  8. values (102, '李四', '男', to_date('01-01-2012', 'dd-mm-yyyy'), '北京','营运', 15000);  
  9. insert into emp2 (ID, NAME, SEX, HIREDATE,BASE, DEPT, SAL)  
  10. values (103, '王五', '男', to_date('01-01-2013', 'dd-mm-yyyy'), '上海','营运', 6000);  
  11. insert into emp2 (ID, NAME, SEX, HIREDATE,BASE, DEPT, SAL)  
  12. values (104, '赵六', '男', to_date('01-01-2014', 'dd-mm-yyyy'), '上海','财务', 10000);  
  13. insert into emp2 (ID, NAME, SEX, HIREDATE,BASE, DEPT, SAL)  
  14. values (105, '小花', '女', to_date('01-08-2014', 'dd-mm-yyyy'), '上海','财务', 4000);  
  15. insert into emp2 (ID, NAME, SEX, HIREDATE,BASE, DEPT, SAL)  
  16. values (106, '小静', '女', to_date('01-01-2015', 'dd-mm-yyyy'), '北京','财务', 6000);  
  17. commit;  

 

 

3.     查看一下刚才插入的数据

 

[sql] view plain copy
  1. select * from emp2;  

 

 

 

4.      先看下普通分组的效果

按照地区统计每个部门的总工资

[sql] view plain copy
  1. select base,dept ,sum(sal) from emp2   
  2. group by base,dept;  

查看结果如下:

 

 

view plain copy
  1. select base,dept,sum(sal) from emp2   
  2. groupbyrollup(base,dept);  

 

 

结果相当于

 

[sql] view plain copy
  1. select base,dept,sum(sal) from emp2   
  2. group by base,dept  
  3. unionall  
  4. select base,null,sum(sal) from emp2   
  5. group by base,null  
  6. unionall  
  7. selectnull,null,sum(sal) from emp2   
  8. group by null,null  
  9. order by 1,2  

如果颠倒下rollup顺序则结果如下:

[sql] view plain copy
  1. select base,dept,sum(sal) from emp2   
  2. group by rollup(dept,base);  

如果在实际查询中,有的小计或合计我们不需要,那么就要使用局部rollup,局部rollup就是将需要固定统计的列放在group by中,而不是放在rollup中。

 

[sql] view plain copy
  1. select base,dept,sum(sal) from emp2   
  2. group by dept,rollup(base);  

与group by rollup(dept,base)相比:去掉了最后一行的汇总,因为每次汇总要么是dept,base,要么是dept,null ,dept是固定的。

如果只希望看到合计则可以这样写:

 

[sql] view plain copy
  1. select base,dept ,sum(sal) from emp2   
  2. group by rollup((base,dept));  

 

view plain copy
  1. select base,dept,sum(sal) from emp2   
  2. group by cube(base,dept)  
  3. order by 1,2;  

 

 

 

部分CUBE和部分ROLLUP类似,把需要固定统计的列放到group by中,不放到cube中就可以了。

如果cube中只有一个列,那么和rollup的结果一致

 

 

[sql] view plain copy
  1. select base,dept,sum(sal) from emp2   
  2. group by dept,cube(base)  
  3. order by1,2;  

 

 

rollup和cube区别:

如果是ROLLUP(A,B, C)的话,GROUP BY顺序

(A、B、C)

(A、B)

(A)

最后对全表进行GROUPBY操作。

如果是GROUP BY CUBE(A, B, C),GROUP BY顺序
(A、B、C)

(A、B)

(A、C)

(A),

(B、C)

(B)

(C),

最后对全表进行GROUPBY操作。

view plain copy
  1. select base,dept,sum(sal) from emp2   
  2. group by grouping sets(base,dept);  

结果为:

 

等价于

 

[sql] view plain copy
  1. select base,null,sum(sal) from emp2   
  2. group by  base,null  
  3. unionall  
  4. select null,dept,sum(sal) from emp2   
  5. group by  null,dept;  

理解了groupingsets的原理我们用他实现rollup的功能也是可以的:

 

[sql] view plain copy
  1. select base,dept,sum(sal) from emp2   
  2. group by grouping sets ((base,dept),dept,null);  

效果如下:

 

view plain copy
  1. select decode(grouping(base),1,'所有地区',base) base,  
  2. decode(grouping(dept),1,'所有部门',dept)dept ,sum(sal) from emp2   
  3. group by rollup(dept,base);