您的位置:首页 > 博客中心 > 数据库 >

Oralce 高级 sql 之 rollup 与 cube

时间:2022-03-14 04:44

在 oracle sql 查询中,oracle 提供了一些高级功能能够简化 sql 查询语句以及提高查询性能。下面将介绍 rollup,cube的用法与区别。

1. rollup

rollup 能够在 select 语句中计算指定分组字段的多个层次的小计以及合计. rollup 非常容易使用并且非常高效。
rollup 从右到左扫描分组字段, 逐步创建更高级别的小计. 最后再创建一行总计. rollup 将创建 n + 1 个层次(级别)的小计, n 指的是 rollup 中的字段数. 



1.1 什么时候使用 rollup

    SQL> create table emp as select * from scott.emp; Table created. SQL> create table dept as select * from scott.dept; Table created. SQL> select * from emp; EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ---------- ---------- --------- ---------- --------- ---------- ---------- ---------- 7369 SMITH CLERK 7902 17-DEC-80 800 20 7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30 7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30 7566 JONES MANAGER 7839 02-APR-81 2975 20 7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30 7698 BLAKE MANAGER 7839 01-MAY-81 2850 30 7782 CLARK MANAGER 7839 09-JUN-81 2450 10 7788 SCOTT ANALYST 7566 19-APR-87 3000 20 7839 KING preSIDENT 17-NOV-81 5000 10 7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30 7876 ADAMS CLERK 7788 23-MAY-87 1100 20 7900 JAMES CLERK 7698 03-DEC-81 950 30 7902 FORD ANALYST 7566 03-DEC-81 3000 20 7934 MILLER CLERK 7782 23-JAN-82 1300 10 14 rows selected. SQL> select * from dept; DEPTNO DNAME LOC ---------- -------------- ------------- 10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON


    如果想统计每个部门每个职位的总薪水,sql 语句如下:

    SQL> select b.dname, a.job, sum(a.sal)
      2  from emp a, dept b
      3  where a.deptno = b.deptno
      4  group by b.dname, a.job;
    
    DNAME          JOB       SUM(A.SAL)
    -------------- --------- ----------
    SALES          MANAGER         2850
    SALES          CLERK            950
    ACCOUNTING     MANAGER         2450
    ACCOUNTING     preSIDENT       5000
    ACCOUNTING     CLERK           1300
    SALES          SALESMAN        5600
    RESEARCH       MANAGER         2975
    RESEARCH       ANALYST         6000
    RESEARCH       CLERK           1900
    
    9 rows selected.

    如果想用一条 sql 语句统计每个部门每个职位的总薪水每个部门的总薪水以及所有部门的总薪水的话,势必要再用一个 group by 语句统计每个部门的总薪水然后再与上面的结果 union 起来才能得到最后的结果,但是这样写的话除了书写会复杂一点外,另外肯定还要多扫描几次 emp 与 dept 表,现在 oracle 提供了 rollup 子句,我们可以先来看看 rollup 子句的结果:
    SQL> select b.dname, a.job, sum(a.sal)
      2  from emp a, dept b
      3  where a.deptno = b.deptno
      4  group by rollup(b.dname, a.job);
    
    DNAME          JOB       SUM(A.SAL)
    -------------- --------- ----------
    SALES          CLERK            950
    SALES          MANAGER         2850
    SALES          SALESMAN        5600
    SALES                          9400
    RESEARCH       CLERK           1900
    RESEARCH       ANALYST         6000
    RESEARCH       MANAGER         2975
    RESEARCH                      10875
    ACCOUNTING     CLERK           1300
    ACCOUNTING     MANAGER         2450
    ACCOUNTING     preSIDENT       5000
    ACCOUNTING                     8750
                                  29025

    从上面的结果中可以看出,rollup 子句会为每个部门增加一行小计以及为所有部门增加一行总计,即统计了每个部门的总薪水以及所有部门的总薪水。

    通常来说,rollup 往往同 group by 语句一起使用,它是 group by 语句的一种扩展。

    • 如果语句为 group by rollup(a, b),oracle 将会从右到左先对字段 a 和 b 先进行 group by,然后对字段 A 进行 group by,最后对全表进行 group by。
    • 如果语句为 group by rollup(a, b, c), oracle 将从右到左先会对字段 a 和 b 和 c 先进行 group by, 然后对字段 a 和 b 进行 group by,然后对字段 a 进行 group by,最后对全表进行 group by。

    下面我们将演示一个 rollup 三个字段的例子:

    SQL> select b.dname, a.job, to_char(hiredate, 'yyyy'), sum(sal)
      2  from emp a, dept b
      3  where a.deptno = b.deptno
      4  group by b.dname, a.job, to_char(hiredate, 'yyyy')
      5  order by 1, 2, 3;
    
    DNAME          JOB       TO_C   SUM(SAL)
    -------------- --------- ---- ----------
    ACCOUNTING     CLERK     1982       1300
    ACCOUNTING     MANAGER   1981       2450
    ACCOUNTING     preSIDENT 1981       5000
    RESEARCH       ANALYST   1981       3000
    RESEARCH       ANALYST   1987       3000
    RESEARCH       CLERK     1980        800
    RESEARCH       CLERK     1987       1100
    RESEARCH       MANAGER   1981       2975
    SALES          CLERK     1981        950
    SALES          MANAGER   1981       2850
    SALES          SALESMAN  1981       5600
    
    11 rows selected.
    
    SQL> select b.dname, a.job, to_char(hiredate, 'yyyy'), sum(sal)
      2  from emp a, dept b
      3  where a.deptno = b.deptno
      4  group by rollup(b.dname, a.job, to_char(hiredate, 'yyyy'));
    
    DNAME          JOB       TO_C   SUM(SAL)
    -------------- --------- ---- ----------
    SALES          CLERK     1981        950
    SALES          CLERK                 950
    SALES          MANAGER   1981       2850
    SALES          MANAGER              2850
    SALES          SALESMAN  1981       5600
    SALES          SALESMAN             5600
    SALES                               9400
    RESEARCH       CLERK     1980        800
    RESEARCH       CLERK     1987       1100
    RESEARCH       CLERK                1900
    RESEARCH       ANALYST   1981       3000
    RESEARCH       ANALYST   1987       3000
    RESEARCH       ANALYST              6000
    RESEARCH       MANAGER   1981       2975
    RESEARCH       MANAGER              2975
    RESEARCH                           10875
    ACCOUNTING     CLERK     1982       1300
    ACCOUNTING     CLERK                1300
    ACCOUNTING     MANAGER   1981       2450
    ACCOUNTING     MANAGER              2450
    ACCOUNTING     preSIDENT 1981       5000
    ACCOUNTING     preSIDENT            5000
    ACCOUNTING                          8750
                                       29025
    
    24 rows selected.

    1.3 部分 rollup(Partial rollup)


    当你只想统计部分字段时, 可以使用部分 rollup. 例如, group by a, rollup(b, c), 这条语句将创建三个(2 + 1)级别的小计. 分别为级别 (a, b, c), 级别 (a, b) 以及级别 (a).

    SQL> select b.dname, a.job, to_char(hiredate, 'yyyy'), sum(sal)
      2  from emp a, dept b
      3  where a.deptno = b.deptno
      4  group by b.dname, rollup(a.job, to_char(hiredate, 'yyyy'));
    
    DNAME          JOB       TO_C   SUM(SAL)
    -------------- --------- ---- ----------
    SALES          CLERK     1981        950
    SALES          CLERK                 950
    SALES          MANAGER   1981       2850
    SALES          MANAGER              2850
    SALES          SALESMAN  1981       5600
    SALES          SALESMAN             5600
    SALES                               9400
    RESEARCH       CLERK     1980        800
    RESEARCH       CLERK     1987       1100
    RESEARCH       CLERK                1900
    RESEARCH       ANALYST   1981       3000
    RESEARCH       ANALYST   1987       3000
    RESEARCH       ANALYST              6000
    RESEARCH       MANAGER   1981       2975
    RESEARCH       MANAGER              2975
    RESEARCH                           10875
    ACCOUNTING     CLERK     1982       1300
    ACCOUNTING     CLERK                1300
    ACCOUNTING     MANAGER   1981       2450
    ACCOUNTING     MANAGER              2450
    ACCOUNTING     preSIDENT 1981       5000
    ACCOUNTING     preSIDENT            5000
    ACCOUNTING                          8750
    
    23 rows selected.


    从上面的结果中可以看出,部分 rollup 产生的结果:

    • 普通的汇总行是由 group by 产生而不是 rollup
    • 不会产生总计


    2. cube


    cube 可以为指定的列创建各种不同组合的小计. 如果指定的列的数量为 n, group by cube 将创建 2 * n 个层次的小计. cube 是一种比 rollup 更细粒度的分组统计语句。先看看 cube 语句的结果:


    2.1 什么时候使用 cube

    • 当需求中有类似 cross-tabular report (交叉报表)时
    • 对于数据仓库中的统计汇总表, rollup 能够简化统计汇总表并且提高查询统计汇总表的速度


    2.2 cube 例子

    SQL> select b.dname, a.job, sum(a.sal)
      2  from emp a, dept b
      3  where a.deptno = b.deptno
      4  group by cube(b.dname, a.job);
    
    DNAME          JOB       SUM(A.SAL)
    -------------- --------- ----------
                                  29025
                   CLERK           4150
                   ANALYST         6000
                   MANAGER         8275
                   SALESMAN        5600
                   preSIDENT       5000
    SALES                          9400
    SALES          CLERK            950
    SALES          MANAGER         2850
    SALES          SALESMAN        5600
    RESEARCH                      10875
    RESEARCH       CLERK           1900
    RESEARCH       ANALYST         6000
    RESEARCH       MANAGER         2975
    ACCOUNTING                     8750
    ACCOUNTING     CLERK           1300
    ACCOUNTING     MANAGER         2450
    ACCOUNTING     preSIDENT       5000
    
    18 rows selected.
    

    从上面的结果可以看出,group by cube(b.dname, a.job) 语句首先统计所有部门的总薪水,然后统计每个职位(a.job)的总薪水,然后统计每个部门(b.dname)的总薪水,最后统计每个部门每个职位(b.dname, a.job)的总薪水。

    • 如果语句为 group by cube(a, b),oracle 首先对字段 a 和 b 进行 group by,然后对字段 a 进行 group by,然后对字段 b 进行 group by,最后对全表进行 group by。
    • 如果语句为 group by cube(a, b, c),oracle 进行分组的字段分别为 (a, b, c),(a, b),(a, c),(b, c),(a),(b),(c),最后对全表的总计

    下面演示 cube 三个字段的例子:
    SQL> select b.dname, a.job, to_char(hiredate, 'yyyy'), sum(sal)
      2  from emp a, dept b
      3  where a.deptno = b.deptno
      4  group by cube(b.dname, a.job, to_char(hiredate, 'yyyy'));
    
    DNAME          JOB       TO_C   SUM(SAL)
    -------------- --------- ---- ----------
                                       29025
                             1980        800
                             1981      22825
                             1982       1300
                             1987       4100
                   CLERK                4150
                   CLERK     1980        800
                   CLERK     1981        950
                   CLERK     1982       1300
                   CLERK     1987       1100
                   ANALYST              6000
                   ANALYST   1981       3000
                   ANALYST   1987       3000
                   MANAGER              8275
                   MANAGER   1981       8275
                   SALESMAN             5600
                   SALESMAN  1981       5600
                   preSIDENT            5000
                   preSIDENT 1981       5000
    SALES                               9400
    SALES                    1981       9400
    SALES          CLERK                 950
    SALES          CLERK     1981        950
    SALES          MANAGER              2850
    SALES          MANAGER   1981       2850
    SALES          SALESMAN             5600
    SALES          SALESMAN  1981       5600
    RESEARCH                           10875
    RESEARCH                 1980        800
    RESEARCH                 1981       5975
    RESEARCH                 1987       4100
    RESEARCH       CLERK                1900
    RESEARCH       CLERK     1980        800
    RESEARCH       CLERK     1987       1100
    RESEARCH       ANALYST              6000
    RESEARCH       ANALYST   1981       3000
    RESEARCH       ANALYST   1987       3000
    RESEARCH       MANAGER              2975
    RESEARCH       MANAGER   1981       2975
    ACCOUNTING                          8750
    ACCOUNTING               1981       7450
    ACCOUNTING               1982       1300
    ACCOUNTING     CLERK                1300
    ACCOUNTING     CLERK     1982       1300
    ACCOUNTING     MANAGER              2450
    ACCOUNTING     MANAGER   1981       2450
    ACCOUNTING     preSIDENT            5000
    ACCOUNTING     preSIDENT 1981       5000
    
    48 rows selected.

    2.3 部分 cube (partial cube)
    部分 cube 类似于部分 rollup, 把列放在 cube 操作符的外面能够限制生成列组合的小计. 例如, group by a, cube(b, c), 这条语句将产生 4 (2 * 2) 个层次的小计, 分别为层次 (a, b, c), 层次 (a, b), 层次 (a, c), 层次 (a). 

    SQL> select b.dname, a.job, to_char(hiredate, 'yyyy'), sum(sal)
      2  from emp a, dept b
      3  where a.deptno = b.deptno
      4  group by b.dname, cube(a.job, to_char(hiredate, 'yyyy'));
    
    DNAME          JOB       TO_C   SUM(SAL)
    -------------- --------- ---- ----------
    SALES                               9400
    SALES                    1981       9400
    SALES          CLERK                 950
    SALES          CLERK     1981        950
    SALES          MANAGER              2850
    SALES          MANAGER   1981       2850
    SALES          SALESMAN             5600
    SALES          SALESMAN  1981       5600
    RESEARCH                           10875
    RESEARCH                 1980        800
    RESEARCH                 1981       5975
    RESEARCH                 1987       4100
    RESEARCH       CLERK                1900
    RESEARCH       CLERK     1980        800
    RESEARCH       CLERK     1987       1100
    RESEARCH       ANALYST              6000
    RESEARCH       ANALYST   1981       3000
    RESEARCH       ANALYST   1987       3000
    RESEARCH       MANAGER              2975
    RESEARCH       MANAGER   1981       2975
    ACCOUNTING                          8750
    ACCOUNTING               1981       7450
    ACCOUNTING               1982       1300
    ACCOUNTING     CLERK                1300
    ACCOUNTING     CLERK     1982       1300
    ACCOUNTING     MANAGER              2450
    ACCOUNTING     MANAGER   1981       2450
    ACCOUNTING     preSIDENT            5000
    ACCOUNTING     preSIDENT 1981       5000
    
    29 rows selected.


热门排行

今日推荐

热门手游