经常写SQL语句的人应该知道Group by语句的主要用法是进行分类汇总,下面是一种它最常见的用法(根据部门、职位分别统计业绩):
- SELECT a.dname,b.job,SUM(b.sal) sum_sal
- FROM dept a,emp b
- WHERE a.deptno = b.deptno
- GROUP BY a.dname,b.job;
- DNAME JOB SUM_SAL
- -------------- --------- ----------
- SALES MANAGER 2850
- SALES CLERK 950
- SALES SALESMAN 5600
- ACCOUNTING MANAGER 2450
- ACCOUNTING PRESIDENT 5000
- ACCOUNTING CLERK 1300
- RESEARCH MANAGER 2975
- RESEARCH ANALYST 6000
- RESEARCH CLERK 1900
- select * from (
- SELECT a.dname,b.job,SUM(b.sal) sum_sal
- FROM dept a,emp b
- WHERE a.deptno = b.deptno
- GROUP BY a.dname,b.job
- UNION ALL
- --实现了部门的小计
- SELECT a.dname,NULL, SUM(b.sal) sum_sal
- FROM dept a,emp b
- WHERE a.deptno = b.deptno
- GROUP BY a.dname
- UNION ALL
- --实现了所有部门总的合计
- SELECT NULL,NULL, SUM(b.sal) sum_sal
- FROM dept a,emp b
- WHERE a.deptno = b.deptno)
- order by dname;
- DNAME JOB SUM_SAL
- -------------- --------- ----------
- ACCOUNTING CLERK 1300
- ACCOUNTING MANAGER 2450
- ACCOUNTING PRESIDENT 5000
- ACCOUNTING 8750
- RESEARCH CLERK 1900
- RESEARCH MANAGER 2975
- RESEARCH ANALYST 6000
- RESEARCH 10875
- SALES CLERK 950
- SALES MANAGER 2850
- SALES SALESMAN 5600
- SALES 9400
- 29025
- union all 合并笨办法产生的执行计划
- -------------------------------------------------------------------------------
- Plan hash value: 2979078843
- -------------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- -------------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 29 | 812 | 23 (22)| 00:00:01 |
- | 1 | SORT ORDER BY | | 29 | 812 | 23 (22)| 00:00:01 |
- | 2 | VIEW | | 29 | 812 | 22 (19)| 00:00:01 |
- | 3 | UNION-ALL | | | | | |
- | 4 | HASH GROUP BY | | 14 | 756 | 8 (25)| 00:00:01 |
- |* 5 | HASH JOIN | | 14 | 756 | 7 (15)| 00:00:01 |
- | 6 | TABLE ACCESS FULL| DEPT | 4 | 88 | 3 (0)| 00:00:01 |
- | 7 | TABLE ACCESS FULL| EMP | 14 | 448 | 3 (0)| 00:00:01 |
- | 8 | HASH GROUP BY | | 14 | 672 | 8 (25)| 00:00:01 |
- |* 9 | HASH JOIN | | 14 | 672 | 7 (15)| 00:00:01 |
- | 10 | TABLE ACCESS FULL| DEPT | 4 | 88 | 3 (0)| 00:00:01 |
- | 11 | TABLE ACCESS FULL| EMP | 14 | 364 | 3 (0)| 00:00:01 |
- | 12 | SORT AGGREGATE | | 1 | 39 | | |
- |* 13 | HASH JOIN | | 14 | 546 | 7 (15)| 00:00:01 |
- | 14 | TABLE ACCESS FULL| DEPT | 4 | 52 | 3 (0)| 00:00:01 |
- | 15 | TABLE ACCESS FULL| EMP | 14 | 364 | 3 (0)| 00:00:01 |
- -------------------------------------------------------------------------------
- SELECT a.dname,b.job, SUM(b.sal) sum_sal
- FROM dept a,emp b
- WHERE a.deptno = b.deptno
- GROUP BY ROLLUP(a.dname,b.job);
- DNAME JOB SUM_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写法产生的执行计划
- -----------------------------------------------------------------------------
- Plan hash value: 1037965942
- -----------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- -----------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 14 | 756 | 8 (25)| 00:00:01 |
- | 1 | SORT GROUP BY ROLLUP| | 14 | 756 | 8 (25)| 00:00:01 |
- |* 2 | HASH JOIN | | 14 | 756 | 7 (15)| 00:00:01 |
- | 3 | TABLE ACCESS FULL | DEPT | 4 | 88 | 3 (0)| 00:00:01 |
- | 4 | TABLE ACCESS FULL | EMP | 14 | 448 | 3 (0)| 00:00:01 |
- -----------------------------------------------------------------------------
这时候,如果又有人跑过来说:除了以上数据,他还需要每个职位总的业绩,你只要把rollup换成cube就可以了,如下所示:
- -- CUBE分组
- SELECT a.dname,b.job, SUM(b.sal) sum_sal
- FROM dept a,emp b
- WHERE a.deptno = b.deptno
- GROUP BY CUBE(a.dname,b.job);
- DNAME JOB SUM_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
这时候,如果又有人跑过来说:他不需要那么细的数据,只需要汇总的数据,可以使用Grouping Sets:
- ---GROUPING SETS分组
- SELECT to_char(b.hiredate,'yyyy') hire_year,a.dname,b.job, SUM(sal) sum_sal
- FROM dept a,emp b
- WHERE a.deptno = b.deptno
- GROUP BY GROUPING SETS(to_char(b.hiredate,'yyyy'),a.dname,b.job);
- HIRE DNAME JOB SUM_SAL
- ---- -------------- --------- ----------
- 1987 4100
- 1980 800
- 1982 1300
- 1981 22825
- ACCOUNTING 8750
- RESEARCH 10875
- SALES 9400
- CLERK 4150
- SALESMAN 5600
- PRESIDENT 5000
- MANAGER 8275
- ANALYST 6000