ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

Oracle笔记 之 Oracle高级分组函数

2021-01-12 09:04:44  阅读:308  来源: 互联网

标签:10 20 30 笔记 MANAGER 分组 Oracle group nvl


高级分组函数

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

ROLLUP(累计累加)

①,ROLLUP是对group by的扩展,它只能出现在group by子句中,依赖分组的列,对每个分组会生成汇总数据。
②,rollup和group by联合使用,达到了按group by列顺序分组,并且实现小计和合计的功能。
③,rollup分组是有序的,先全部分组,然后对每个分组小计,最后合计。
④,rollup中列的顺序不同,统计的结果不同。因为它是按列从右递减分组的。
例如 Group by ROLLUP(A, B, C),首先会对(A、B、C)进行GROUP BY,然后对(A、B)进行GROUP BY,然后是(A)进行GROUP BY,最后对全表进行GROUP BY操作
例如:

select deptno,
       job,
       sum(nvl(sal, 0)),
       sum(nvl(comm, 0)),
       sum(nvl(sal, 0) + nvl(comm, 0))
  from emp
 group by rollup(deptno, job)
# 结果
1	10	CLERK	1300	0	1300
2	10	MANAGER	2450	0	2450
3	10	PRESIDENT	5000	0	5000
4	10		8750	0	8750
5	20	CLERK	1900	0	1900
6	20	ANALYST	6000	0	6000
7	20	MANAGER	2975	0	2975
8	20		10875	0	10875
9	30	CLERK	950	0	950
10	30	MANAGER	2850	0	2850
11	30	SALESMAN	5600	2200	7800
12	30		9400	2200	11600
13			29025	2200	31225

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

select deptno,
       job,
       sum(nvl(sal, 0)),
       sum(nvl(comm, 0)),
       sum(nvl(sal, 0) + nvl(comm, 0))
  from emp
 group by deptno, rollup(job)
# 结果
1	10	CLERK	1300	0	1300
2	10	MANAGER	2450	0	2450
3	10	PRESIDENT	5000	0	5000
4	10		8750	0	8750
5	20	CLERK	1900	0	1900
6	20	ANALYST	6000	0	6000
7	20	MANAGER	2975	0	2975
8	20		10875	0	10875
9	30	CLERK	950	0	950
10	30	MANAGER	2850	0	2850
11	30	SALESMAN	5600	2200	7800
12	30		9400	2200	11600

⑥,如果只看合计部分,需要将分组列使用()包括。
例如:

select deptno,
       job,
       sum(nvl(sal, 0)),
       sum(nvl(comm, 0)),
       sum(nvl(sal, 0) + nvl(comm, 0))
  from emp
 group by rollup((deptno, job))
# 结果
1	10	CLERK	1300	0	1300
2	10	MANAGER	2450	0	2450
3	10	PRESIDENT	5000	0	5000
4	20	CLERK	1900	0	1900
5	20	ANALYST	6000	0	6000
6	20	MANAGER	2975	0	2975
7	30	CLERK	950	0	950
8	30	MANAGER	2850	0	2850
9	30	SALESMAN	5600	2200	7800
10			29025	2200	31225

CUBE(交叉列表)

①,CUBE也是对group by运算的一种扩展,它比rollup扩展更加精细,组合类型更多。
②,rollup是按组合的列从右到左递减分组,CUBE则是对所有可能的组合情况进行分组。
cube是各种可能情况的组合,只不过统计的结果顺序不同而已,rollup按组合的列从右到左递减分组,列的顺序不同,则结果不同。
注意:要想结果符合浏览习惯最好在cube扩展后增加order by子句。
③,cube的分组的情况更多,覆盖所有的可能分组,并计算所有可能的分组的小计。
④,对于CUBE来说,只要列的名字一样,无所谓顺序,结果都是一样的。

例如:

select deptno,
       job,
       sum(nvl(sal, 0)),
       sum(nvl(comm, 0)),
       sum(nvl(sal, 0) + nvl(comm, 0))
  from emp
 group by cube(deptno, job)
 order by 1, 2 nulls last
# 结果
1	10	CLERK	1300	0	1300
2	10	MANAGER	2450	0	2450
3	10	PRESIDENT	5000	0	5000
4	10		8750	0	8750
5	20	ANALYST	6000	0	6000
6	20	CLERK	1900	0	1900
7	20	MANAGER	2975	0	2975
8	20		10875	0	10875
9	30	CLERK	950	0	950
10	30	MANAGER	2850	0	2850
11	30	SALESMAN	5600	2200	7800
12	30		9400	2200	11600
13		ANALYST	6000	0	6000
14		CLERK	4150	0	4150
15		MANAGER	8275	0	8275
16		PRESIDENT	5000	0	5000
17		SALESMAN	5600	2200	7800
18			29025	2200	31225

⑤,cube的语法和rollup一样,部分cube和只显示合计部分请参照rollup扩展。

grouping函数

用rollup和cube函数都会对结果集产生null,这时候可用grouping函数来确认该记录是由哪个字段得出来的。
grouping函数带一个参数,必须为group by中出现的某一列,参数为字段名,结果是根据该字段得出来的就返回1,反之返回0。
例如:

select decode(grouping(deptno), 1, 'ALL DEPT', deptno),
       decode(grouping(job), 1, 'ALL JOB', job),
       sum(nvl(sal, 0)),
       sum(nvl(comm, 0)),
       sum(nvl(sal, 0) + nvl(comm, 0))
  from emp
 group by rollup(deptno, job)
# 结果
1	10	CLERK	1300	0	1300
2	10	MANAGER	2450	0	2450
3	10	PRESIDENT	5000	0	5000
4	10	ALL JOB	8750	0	8750
5	20	CLERK	1900	0	1900
6	20	ANALYST	6000	0	6000
7	20	MANAGER	2975	0	2975
8	20	ALL JOB	10875	0	10875
9	30	CLERK	950	0	950
10	30	MANAGER	2850	0	2850
11	30	SALESMAN	5600	2200	7800
12	30	ALL JOB	9400	2200	11600
13	ALL DEPT	ALL JOB	29025	2200	31225

grouping_id函数

grouping_id函数的参数可以是多个,但必须为group by中出现的列。
Grouping_id()的返回值其实就是参数中的每列的grouping()值的二进制向量,例如如果grouping(A)=1,grouping(B)=1,则grouping_id(A,B)的返回值就是二进制的11,转成11进制就是3。
例如:

select decode(grouping_id(deptno, job), 1, 'Subtotal', 3, 'Total', deptno),
       job,
       sum(nvl(sal, 0)),
       sum(nvl(comm, 0)),
       sum(nvl(sal, 0) + nvl(comm, 0))
  from emp
 group by rollup(deptno, job)
# 结果
1	10	CLERK	1300	0	1300
2	10	MANAGER	2450	0	2450
3	10	PRESIDENT	5000	0	5000
4	Subtotal		8750	0	8750
5	20	CLERK	1900	0	1900
6	20	ANALYST	6000	0	6000
7	20	MANAGER	2975	0	2975
8	Subtotal		10875	0	10875
9	30	CLERK	950	0	950
10	30	MANAGER	2850	0	2850
11	30	SALESMAN	5600	2200	7800
12	Subtotal		9400	2200	11600
13	Total		29025	2200	31225

group_id函数

group_id()函数,无参数,group by对某些列的集合会进行重复的grouping,而实际上绝大多数情况下对结果集中的这些重复grouping是不需要的,就必须有办法剔出这些重复grouping行。
当结果集中有n条重复grouping而形成的行时,每行的group_id()分别是0,1,…,n,这样我们在条件中加入一个group_id()<1就可以剔出这些重复grouping的行了。
例如:

select group_id(),
       decode(grouping_id(deptno, job), 1, 'Subtotal', 3, 'Total', deptno),
       job,
       sum(nvl(sal, 0)),
       sum(nvl(comm, 0)),
       sum(nvl(sal, 0) + nvl(comm, 0))
  from emp
 group by deptno, rollup(deptno, job)
# 结果
1	0	10	CLERK	1300	0	1300
2	0	10	MANAGER	2450	0	2450
3	0	10	PRESIDENT	5000	0	5000
4	0	20	CLERK	1900	0	1900
5	0	20	ANALYST	6000	0	6000
6	0	20	MANAGER	2975	0	2975
7	0	30	CLERK	950	0	950
8	0	30	MANAGER	2850	0	2850
9	0	30	SALESMAN	5600	2200	7800
10	0	Subtotal		8750	0	8750
11	0	Subtotal		10875	0	10875
12	0	Subtotal		9400	2200	11600
13	1	Subtotal		8750	0	8750
14	1	Subtotal		10875	0	10875
15	1	Subtotal		9400	2200	11600

使用 group_id()<1过滤后:

select group_id(),
       decode(grouping_id(deptno, job), 1, 'Subtotal', 3, 'Total', deptno),
       job,
       sum(nvl(sal, 0)),
       sum(nvl(comm, 0)),
       sum(nvl(sal, 0) + nvl(comm, 0))
  from emp
 group by deptno, rollup(deptno, job)
having group_id() < 1
# 结果
1	0	10	CLERK	1300	0	1300
2	0	10	MANAGER	2450	0	2450
3	0	10	PRESIDENT	5000	0	5000
4	0	20	CLERK	1900	0	1900
5	0	20	ANALYST	6000	0	6000
6	0	20	MANAGER	2975	0	2975
7	0	30	CLERK	950	0	950
8	0	30	MANAGER	2850	0	2850
9	0	30	SALESMAN	5600	2200	7800
10	0	Subtotal		8750	0	8750
11	0	Subtotal		10875	0	10875
12	0	Subtotal		9400	2200	11600

标签:10,20,30,笔记,MANAGER,分组,Oracle,group,nvl
来源: https://blog.csdn.net/weixin_50648794/article/details/112505447

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有