在查询结果集中使用GROUP BY子句对记录进行分组。在SELECT语句中,GROUP BY子句位于FROM子句之后,其语法格式如下:
SELECT columns_list
FROM table_name
[WHERE conditional_expression]
GROUP BY columns_list
columns_list:字段列表,在GROUP BY子句中也可以指定多个列分组。 table_name:表名。 conditional_expression:筛选条件表达式。
1. 使用GROUP BY子句进行单列分组
单列分组是指基于列生成分组统计结果。进行单列分组时,会基于分组列的每个不同值生成一个统计结果。
--在emp表中,按照部门编号(deptno)列进行分组,并显示每个部门有几个岗位
select deptno,count(*) as 岗位数 from emp group by deptno order by deptno;

GROUP BY子句经常与聚集函数一起使用。使用GROUP BY子句和聚集函数,可以实现对查询结果中每一组数据进行分类统计。在Oracle系统中,经常使用的统计函数及其说明如下表:

--在emp表中,使用GROUP BY子句对工资记录进行分组,并计算平均工资(AVG)、所有工资的总和(SUM)、最高工资(MAX)和各组的行数(COUNT)
select job 岗位,avg(sal) 平均工资,sum(sal) 工资总和,max(sal) 最高工资,count(job) 岗位数 from emp group by job;

使用GROUP BY子句时的注意事项:
在SELECT子句的后面只可以有统计函数和进行分组的列名两类表达式。 SELECT子句中的列名必须是进行分组的列,但是GROUP BY子句后面的列名可以不出现在SELECT子句中。 默认按照GROUP BY子句指定的分组列升序排列,可以使用ORDER BY子句指定新的排列顺序。 如果在一个查询中使用了分组函数,则查询中的任何不在分组函数中的列或表达式必须在GROUP BY子句中出现。
下面是一个错误示例:
--查询岗位(job)和岗位的平均工资
select job,avg(sal) from emp;
没有使用GROUP BY子句,出现错误,提示job不是单分组函数;查询的job是多条数据,而avg(sal)只有一条数据,这两个查询要求是矛盾的;

使用GROUP BY子句改正上面的错误:
--查询岗位(job)和岗位的平均工资
select job,avg(sal) from emp group by job;
通过group by子句将job列按相同数据进行分组,然后avg(sal)计算出每一组的平均工资;

2. 使用GROUP BY子句进行多列分组
多列分组是指基于两个或两个以上的列生成分组统计结果。
--查询emp表,显示每个部门每种岗位的平均工资和最高工资
select deptno,job,avg(sal),max(sal) from emp group by deptno,job;

3. 使用ORDER BY子句改变分组排序结果
GROUP BY子句执行分组统计时,会自动基于分组列进行升序排列。使用ORDER BY子句可以改为降序;
--查询每个部门的部门编号和工资总额按默认排序排列
select deptno,sum(sal) from emp group by deptno
--查询每个部门的部门编号和工资总额并按降序排列
select deptno,sum(sal) from emp group by deptno order by sum(sal) desc;

4. 使用HAVING子句限制分组结果
GROUP BY子句进行分组的结果可使用HAVING子句对分组的结果做进一步的筛选。
--查询部门平均工资高于1000的部门编号和平均工资
select deptno as 部门编号,avg(sal) as 平均工资
from emp
group by deptno
having avg(sal) > 1000 ;

5. 在GROUP BY子句中使用ROLLUP和CUBE操作符
使用ROLLUP操作符创建多层次的汇总数据
ROLLUP操作符在Oracle中用于生成分组汇总报表,它可以在GROUP BY子句中指定多个列,并生成这些列的所有可能组合的汇总行。
-- 显示每个部门的平均工资、所有员工的平均工资
select deptno as 部门编号, job as 岗位, avg(sal) as 平均工资
from emp
group by rollup(deptno,job) ;

使用CUBE操作符根据指定的列列表生成不同的排列组合,并根据每一种组合结果生成统计汇总
--显示各岗位的平均工资、每个部门的平均工资、所有员工的平均工资
select deptno as 部门编号, job as 岗位, avg(sal) as 平均工资
from emp
group by cube(deptno,job) ;

使用GROUPING函数确定统计结果是否使用了特定列
当使用ROLLUP或者CUBE操作符生成统计结果时,某个统计结果行可能用到一列或者多列,也可能没有使用任何列。使用GROUPING函数确定统计结果是否使用了特定列。如果该函数返回0,则表示统计结果使用了该列;如果函数返回1,则表示统计结果没有使用该列。
--使用GROUPING函数确定统计结果所使用的列
select deptno,job, sum (sal),grouping(deptno),grouping(job)
from emp
group by rollup(deptno,job) ;

在ROLLUP操作符中使用复合列
复合列被看作一个逻辑单元的列组合,当引用复合列时,需要用括号括住相关列。通过在ROLLUP操作符中使用复合列,可以略过ROLLUP操作符的某些统计结果。
例如,子句GROUP BY ROLLUP(a,b,c)的统计结果等同于GROUP BY(a,b,c)、GROUP BY(a,b)、GROUP BY a以及GROUP BY()的并集;而如果将(b,c)作为复合列,那么子句GROUP BY ROLLUP(a,(b,c))的结果等同于GROUP BY(a,b,c)、GROUP BY a以及GROUP BY()的并集。
--在emp表中显示特定部门特定岗位的工资总额以及所有员工的工资总额
select deptno,job, sum (sal) from emp group by rollup((deptno,job)) ;
--显示特定部门特定岗位的工资总额、部门的工资总额及所有员工的工资总额
select deptno,job, sum (sal) from emp group by rollup(deptno,job) ;
group by rollup((deptno,job)) 等同于group by(deptno,job)与group by()的并集,即特定部门特定岗位的工资总额与所有员工的工资总额的并集,不包括部门工资总额;

在CUBE操作符中使用复合列
通过在CUBE操作符中使用复合列,可以略过CUBE操作符的某些统计结果。
例如,子句GROUP BY CUBE(a,b,c)的统计结果等同于GROUP BY(a,b,c)、GROUP BY(a,b)、GROUP BY(a,c)、GROUP BY(b,c)、GROUP BY a、GROUP BY b、GROUP BY c以及GROUP BY()的并集;而如果将(a,b)作为复合列,那么子句GROUP BY CUBE((a,b),c)的结果等同于GROUP BY(a,b,c)、GROUP BY(a,b)、GROUP BY c以及GROUP BY()的并集。
--在CUBE操作符中使用复合列,在emp表中显示特定部门特定岗位的工资总额以及所有员工的工资总额
select deptno,job, sum (sal) from emp group by cube ((deptno,job)) ;

使用GROUPING SETS操作符合并多个分组的统计结果
--使用部门编号(deptno)执行分组统计每个部门的平均工资
select deptno,avg (sal) from emp group by deptno;
--使用岗位(job)显示每个岗位的平均工资
select job,avg (sal) from emp group by job ;
--使用grouping sets显示部门的平均工资和岗位的平均工资
select deptno,job,avg (sal) from emp group by grouping sets(deptno,job);
使用grouping sets(deptno,job)既显示了部门平均工资,又同时显示了岗位平均工资;

今天的文章就到这里,感谢各位的点赞、在看。




