MiBDP,数据开发、项目团队、数据应用和产品在路上,金融保险、互联网网游、电商、新零售行业、大数据和AI在路上。对数仓、模型、ETL、数据产品应用了解。DTCC 2013演讲嘉宾,曾做过两款大获好评的数据产品平台。知识星球ID:35863277
分类: Oracle
2007-01-05 16:56:39
1.ROLLUP子句
ROLLUP是GROUP BY子句的扩展,它是为每一个分组返回一条合计记录,并为全部分组返回总计。下面举例说明:
EG:
select * from employees2;
EMPLOYEE_ID DIVISI JOB_ID FIRST_NAME LAST_NAME SALARY
----------- ------ ------ -------------------- -------------------- ----------
1 BUS PRE James Smith 800000
2 SAL MGR Ron Johnson 350000
3 SAL WOR Fred
4 SUP MGR Susan Jones 200000
5 SAL WOR Rob Green 350000
6 SUP WOR Jane Brown 200000
7 SUP MGR John Grey 265000
8 SUP WOR Jean Blue 110000
9 SUP WOR Henry Heyson 125000
10 OPE MGR Kevin Black 225000
11 OPE MGR Keith Long 165000
12 OPE WOR Frank Howard 125000
13 OPE WOR Doreen Penn 145000
14 BUS MGR Mark Smith 155000
15 BUS MGR Jill Jones 175000
16 OPE ENG Megan Craig 245000
17 SUP TEC Matthew Brant 115000
18 OPE MGR Tony Clerke 200000
19 BUS MGR Tanya
20 OPE MGR Terry Cliff 215000
21 SAL MGR Steve Green 275000
22 SAL MGR
23 SAL MGR Sandra Smith 335000
24 SAL MGR Gail Silver 225000
25 SAL MGR Gerald Gold 245000
27 SAL MGR Doreen
28 SAL MGR Jack
29 SAL MGR Paul Owens 245000
30 SAL MGR Melanie
31 SAL MGR
32 SAL MGR Sarah White 235000
33 SAL MGR Terry Iron 225000
34 SAL MGR Christine Brown 247000
35 SAL MGR John Brown 249000
36 SAL MGR Kelvin
37 BUS WOR Damon Jones 280000
已选择37行。
首先我们来看单独的GROUP BY语句:
select division_id,SUM(salary) from employees2
group by division_id;
DIVISI SUM(SALARY)
------ -----------
BUS 1610000
OPE 1320000
SAL 4936000
SUP 1015000
接下来是扩展了的ROLLUP的使用:
select division_id,SUM(salary) from employees2
group by ROLLUP(division_id);
DIVISI SUM(SALARY)
------ -----------
BUS 1610000
OPE 1320000
SAL 4936000
SUP 1015000
8881000
再来看个例子:
select division_id,job_id,SUM(salary)
from employees2
group by ROLLUP(division_id,job_id);
DIVISI JOB_ID SUM(SALARY)
------ ------ -----------
BUS MGR 530000
BUS PRE 800000
BUS WOR 280000
BUS 1610000
OPE ENG 245000
OPE MGR 805000
OPE WOR 270000
OPE 1320000
SAL MGR 4446000
SAL WOR 490000
SAL 4936000
SUP MGR 465000
SUP TEC 115000
SUP WOR 435000
SUP 1015000
8881000
小结:扩展了一个rollup子句带来了分组的一个合计。
2.CUBE子句
CUBE子句也是对GROUP BY子句进行扩展,返回CUBE中所有列组合的小计信息,同时在最后显示总计信息。
EG:
select division_id,job_id,SUM(salary)
from employees2
group by CUBE(division_id,job_id)
order by division_id;
DIVISI JOB_ID SUM(SALARY)
------ ------ -----------
BUS MGR 530000
BUS PRE 800000
BUS WOR 280000
BUS 1610000
OPE ENG 245000
OPE MGR 805000
OPE WOR 270000
OPE 1320000
SAL MGR 4446000
SAL WOR 490000
SAL 4936000
SUP MGR 465000
SUP TEC 115000
SUP WOR 435000
SUP 1015000
ENG 245000
MGR 6246000
PRE 800000
TEC 115000
WOR 1475000
8881000
结:CUBE这里的使用与ROLLUP基本相同,但CUBE的合计更加详细,它能够显示次分组字段的合计信息(job_id)
3.GROUPING()函数与ROLLUP、CUBE的结合使用
GROUPING()可接受一个列值,当列值为空时,函数返回1;如果列值非空,则返回0。(注意:GROUPING只能在ROLLUP、CUBE查询中使用。还可以结合DECODE()函数来注释使用更好)
现在我们把上面的一个例子改一下;
select GROUPING(division_id), division_id,SUM(salary)
from employees2
group by ROLLUP(division_id);
GROUPING(DIVISION_ID) DIVISI SUM(SALARY)
--------------------- ------ -----------
0 BUS 1610000
0 OPE 1320000
0 SAL 4936000
0 SUP 1015000
1 8881000
下面再用DECODE()函数来转换下更好:
select DECODE(GROUPING(division_id),1,'All divisions',division_id)AS div,
division_id,SUM(salary)
from employees2
group by ROLLUP(division_id);
DIV DIVISI SUM(SALARY)
-------------------------- ------ -----------
BUS BUS 1610000
OPE OPE 1320000
SAL SAL 4936000
SUP SUP 1015000
All divisions 8881000
哈哈,这样看下更清晰明了
再举例CUBE与GROUPING()结合的使用
select
DECODE(GROUPING(division_id),1,'All divisions',division_id)AS div,
DECODE(GROUPING(job_id),1,'All jobs',job_id) AS job,
SUM(salary)
from employees2
group by CUBE(division_id,job_id)
order by division_id;
DIV JOB SUM(SALARY)
-------------------------- ---------------- -----------
BUS MGR 530000
BUS PRE 800000
BUS WOR 280000
BUS All jobs 1610000
OPE ENG 245000
OPE MGR 805000
OPE WOR 270000
OPE All jobs 1320000
SAL MGR 4446000
SAL WOR 490000
SAL All jobs 4936000
SUP MGR 465000
SUP TEC 115000
SUP WOR 435000
SUP All jobs 1015000
All divisions ENG 245000
All divisions MGR 6246000
All divisions PRE 800000
All divisions TEC 115000
All divisions WOR 1475000
All divisions All jobs 8881000
已选择21行。
2)下面使用GROUPING SETS子句来限制只返回小计记录。例如下:
select division_id,job_id,SUM(salary)
from employees2
group by GROUPING SETS(division_id,job_id);
DIVISI JOB_ID SUM(SALARY)
------ ------ -----------
BUS 1610000
OPE 1320000
SAL 4936000
SUP 1015000
ENG 245000
MGR 6246000
PRE 800000
TEC 115000
WOR 1475000
已选择9行。
4.GROUPING_ID()函数的使用
GROUPING_ID()函数可接受一列或多列,它返回GROUPING位向量的十进制值。GROUPING位向量的计算方法是按照顺序对每一列调用GROUPING()函数的结果组合起来。它的作用是借助HAVING子句对记录进行过滤,将不包含小计或总计的记录除去。
GROUPING位向量的十进制值,我们由前面的介绍已知道当GROUPING()的列值为空时它返回1,当非空时返回0;
比如:division_id,job_id两列都为非空,GROUPING()都返回0。将这两列的值组合起来,形成一个位向量00,十进制为0。即,当division_id,job_id都非空时,GROUPING_ID()返回0。(这里要特别注意division_id与job_id两列的顺序)下面举个例子:
select division_id,job_id,
GROUPING(division_id) AS div_grp,
GROUPING(job_id) AS job_grp,
GROUPING_ID(division_id,job_id) AS grp_id,
SUM(salary)
from employees2
group by CUBE(division_id,job_id)
order by division_id;
DIVISI JOB_ID DIV_GRP JOB_GRP GRP_ID SUM(SALARY)
------ ------ ---------- ---------- ---------- -----------
BUS MGR 0 0 0 530000
BUS PRE 0 0 0 800000
BUS WOR 0 0 0 280000
BUS 0 1 1 1610000
OPE ENG 0 0 0 245000
OPE MGR 0 0 0 805000
OPE WOR 0 0 0 270000
OPE 0 1 1 1320000
SAL MGR 0 0 0 4446000
SAL WOR 0 0 0 490000
SAL 0 1 1 4936000
SUP MGR 0 0 0 465000
SUP TEC 0 0 0 115000
SUP WOR 0 0 0 435000
SUP 0 1 1 1015000
ENG 1 0 2 245000
MGR 1 0 2 6246000
PRE 1 0 2 800000
TEC 1 0 2 115000
WOR 1 0 2 1475000
1 1 3 8881000
已选择21行。
下面是一个使用GROUPING_ID过滤不包含小计或总计的记录的例子:
select division_id,job_id,
GROUPING_ID(division_id,job_id) AS grp_id,
SUM(salary)
from employees2
group by CUBE(division_id,job_id)
having grouping_id(division_id,job_id)>0
order by division_id;
DIVISI JOB_ID GRP_ID SUM(SALARY)
------ ------ ---------- -----------
BUS 1 1610000
OPE 1 1320000
SAL 1 4936000
SUP 1 1015000
ENG 2 245000
MGR 2 6246000
PRE 2 800000
TEC 2 115000
WOR 2 1475000
3 8881000
好了这次对聚合函数GROUP BY的扩展使用到此,下次对分析函数做下总结