Bootstrap

分组函数之rollup、cube函数、grouping sets函数

一、rollup介绍

rollup 通常和group by语句一起使用,是根据维度在分组的结果集中进行聚合操作(通常为汇总,这取决于SELECT后的聚合函数)。最常用的场景是:为每个分组返回一个小计,同时为所有分组返回总计。

在oracle中,rollup有一下使用方式:

1、不带rollup的goup by :
Group by A ,B产生的分组种数:1种;

  • group by A,B

返回结果集:也就是这一种分组的结果集。

2、带rollup但group by与rollup之间没有任何内容:

1)Group by rollup(A ,B) 产生的分组种数:3种;

  • 第一种:group by A,B
  • 第二种:group by A
  • 第三种:group by NULL

返回结果集:为以上三种分组统计结果集的并集且未去掉重复数据。

2)Group by rollup(A ,B,C) 产生的分组种数:4种;

  • 第一种:group by A,B,C
  • 第二种:group by A,B
  • 第三种:group by A
  • 第四种:group by NULL

    返回结果集:为以上四种分组统计结果集的并集且未去掉重复数据。

3、带rollup但group by与rollup之间还包含有列信息 :

1)Group by A , rollup(A ,B) 产生的分组种数:3种;

  • 第一种:group by A,A,B 等价于group by A,B
  • 第二种:group by A,A 等价于group by A
  • 第三种:group by A,NULL 等价于group by A

返回结果集:为以上三种分组统计结果集的并集且未去掉重复数据。

2)Group by C , rollup(A ,B) 产生的分组种数:3种;

  • 第一种:group by C,A,B
  • 第二种:group by C,A
  • 第三种:group by C,NULL 等价于group by C

返回结果集:为以上三种分组统计结果集的并集且未去掉重复数据。

4、带rollup且rollup子句括号内又使用括号对列进行组合:

1)Group by rollup((A ,B)) 产生的分组种数:2种;

  • 第一种:group by A,B
  • 第二种:group by NULL

返回结果集:为以上两种分组统计结果集的并集且未去掉重复数据。

2)Group by rollup(A ,(B,C)) 产生的分组种数:3种;

  • 第一种:group by A,B,C
  • 第二种:group by A
  • 第三种:group by NULL

返回结果集:为以上三种分组统计结果集的并集且未去掉重复数据。

对这种情况,可以理解为几个列被括号括在一起时,就只能被看成一个整体,分组时不需要再细化。因此也可推断rollup括号内也顶多加到一重括号,加多重了应该没有任何意义(这个推断我没有做验证的哦)。

其他:

  1. rollup的功能可以使用多个group by和union来实现;
  2. mysql中也有with rollup语法,但比较简单。只实现了上面的第二种功能。而且oracle中rollup可以和order by一起使用(mysql中不可以)

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
SQL> select ename,deptno,sum(sal) from emp group by rollup(deptno,ename);

ENAME	       DEPTNO	SUM(SAL)
---------- ---------- ----------
KING		   10	    5000
CLARK		   10	    2450
MILLER		   10	    1300
		       10	    8750
FORD		   20	    3000
ADAMS		   20	    1100
JONES		   20	    2975
SCOTT		   20	    3000
SMITH		   20	     800
		       20	   10875
WARD		   30	    1250

ENAME	       DEPTNO	SUM(SAL)
---------- ---------- ----------
ALLEN		   30	    1600
BLAKE		   30	    2850
JAMES		   30	     950
MARTIN		   30	    1250
TURNER		   30	    1500
		       30	    9400
			            29025
1
2
3
4
5
select decode(grouping(f_line)+grouping(f_workarea),1,'小计',2,'总计',f_workarea) f_workarea,
decode(grouping(f_line),1,count(*)||'条',f_line) f_line,
sum(f_pagesnumber) sum_pagesnumbers  
from t_testcount 
group by rollup (f_workarea,f_line);

二、rollup的几个辅助函数

  • grouping()函数:

    必须接受一列且只能接受一列做为其参数。参数列值为空返回1,参数列值非空返回0。(如果参数的列在rollup中,则返回1;否则返回0)

  • grouping_id()函数:

    必须接受一列或多列做为其参数。返回值为按参数排列顺序,依次对各个参数使用grouping()函数,并将结果值依次串成一串二进制数然后再转化为十进制所得到的值。

例如:grouping(A) = 0 ; grouping(B) = 1;
则:grouping_id(A,B) = (01)2 = 1;
grouping_id(B,A) = (10)2 =2;

  • group_id()函数

    调用时不需要且不能传入任何参数。返回值为某个特定的分组出现的重复次数(第一大点中的第3种情况中往往会产生重复的分组)。重复次数从0开始,例如某个分组第一次出现则返回值为0,第二次出现时返回值为1,……,第n次出现返回值为n-1。

注:使用以上三个函数往往是为了过滤掉一部分统计数据,而达到美化统计结果的作用。

三、rollup和cube的区别

rollup是cube的一种特殊情况,和rollup一样,cube也是根据维度在分组的结果集中进行聚合操作。但是rollup只在层次上对数据进行聚合,而cube对所有的维度进行聚合。具有N个维度的列,cube需要2的N次方次分组操作,而rollup只需要N次分组操作。

带cube子句的group by会产生更多的分组统计数据。cube后的列有多少种组合(注意组合是与顺序无关的)就会有多少种分组。

  1. 假设有n个维度,rollup会有n个聚合:
    rollup(a,b) 统计列包含:(a,b)、(a)、()
    rollup(a,b,c) 统计列包含:(a,b,c)、(a,b)、(a)、()
    ……以此类推ing……

  2. 假设有n个纬度,cube会有2的n次方个聚合:
    cube(a,b) 统计列包含:(a,b)、(a)、(b)、()
    cube(a,b,c) 统计列包含:(a,b,c)、(a,b)、(a,c)、(b,c)、(a)、(b)、(c)、()
    ……以此类推ing……

四、grouping sets(…) 介绍

oracle中,允许在group by后面使用 grouping sets(…) 语句。通过该语句可以实现rollup、cube同样的功能。

  1. Group by grouping sets(A ,B) 产生的分组种数:2种;
    • 第一种:group by A
    • 第二种:group by B

返回结果集:为以上两种分组统计结果集的并集且未去掉重复数据。

  1. Group by grouping sets ((A ,B),A) 产生的分组种数:2种;
    • 第一种:group by A,B,A 等价于group by A,B
    • 第二种:group by A,NULL 等价于group by A

返回结果集:为以上二种分组统计结果集的并集且未去掉重复数据。

rollup函数(分组后对每组数据分别合计)

  • 需求:sql通过分组查询后,对每组数据进行小计,然后对总的数据总计
  • rollup的作用:
    用 ROLLUP 汇总数据,在生成包含小计和合计的报表时,ROLLUP 运算符很有用。
  • 例子:
  • SQL> select deptno,job,sum(sal) from emp group by deptno,job order by deptno;
     2 单独使用分组查询
     3  
     4 DEPTNO JOB         SUM(SAL)
     5 ------ --------- ----------
     6     10 CLERK           1300
     7     10 MANAGER         2450
     8     10 PRESIDENT       5000
     9     20 ANALYST         6000
    10     20 CLERK           1900
    11     20 MANAGER         2975
    12     30 CLERK            950
    13     30 MANAGER         2850
    14     30 SALESMAN        5600
    15  
    16 已选择9行。
    
    使用rollup函数分组:
    SQL> select deptno,job,sum(sal) from emp group by rollup(deptno,job) order by deptno;
    19  
    20 DEPTNO JOB         SUM(SAL)
    21 ------ --------- ----------
    22     10 CLERK           1300 第一次分组的sum总和计算
    23     10 MANAGER         2450
    24     10 PRESIDENT       5000
    25     10                 8750 第二次分组添加的计算(分组小计)
    26     20 ANALYST         6000
    27     20 CLERK           1900
    28     20 MANAGER         2975
    29     20                10875
    30     30 CLERK            950
    31     30 MANAGER         2850
    32     30 SALESMAN        5600
    33     30                 9400
    34                       29025 第三次分组添加的计算(总计)
    35 所以rollup函数进行多次分组计算
    36  
    37 已选择13行。
    

cube函数

;