SQL Fundamentals: 分组统计查询(FROM-WHERE-GROUPBY-HAVING-SELECT-ORDER BY)
SQL Fundamentals || Oracle SQL语言
统计函数
单字段分组统计(GROUP BY)
多字段分组统计
HAVING子句
- 控制操作的显示列:基本的SELECT语句
- 控制行:限定查询和排序显示
- 分组统计查询
各个子句的执行顺序:
1、FROM-->
2、WHERE -->
3、GROUP BY(HAVING子句)-->
4、SELECT-->
5、ORDER BY-->
一、统计函数/分组函数,
只有前5个是标准统计函数,其他的是扩展函数
五个核心的统计函数:COUNT()、AVG()、SUM()、MIN()、MAX()
只有COUNT()函数可以在表中没有任何记录时返回数字结果.
组函数 |
描述 |
COUNT(* | [DISTINCT] 列) |
求出全部的记录数 |
SUM(列) |
求出总和,操作的列是数字 |
AVG(列) |
平均值 |
MAX(列) |
最大值 |
MIN(列) |
最小值 |
MEDIAN(列) |
返回中间值() |
VARIANCE(列) |
返回方差 |
STDDEV(列) |
返回标准差 |
统计出公司的雇员人数
SELECT COUNT(empno) , COUNT(*) FROM emp ;
对于COUNT()函数而言,可以传递三种内容:
COUNT(*) |
|
COUNT(字段) |
如果列上存在null,那么null不会进行统计 适用于不可能为null的列进行统计. |
COUNT(DISTINCT字段) |
如果列上有重复,那么重复记录不统计 |
验证COUNT(*)、COUNT(字段)、COUNT(DISTINCT 字段)的使用区别
SELECT COUNT(*) , COUNT(ename) , COUNT(comm) , COUNT(DISTINCT job) FROM emp ;
验证三种COUNT()函数的使用方式(COUNT()永远有数据返回)
SELECT COUNT(ename) , AVG(sal) , SUM(sal) , MAX(sal) , MIN(sal) FROM bonus ;
- 例子:查询每个月工资总和
- SQL> SELECT SUM(sal) FROM emp;
- 例子:查询平均工资,最高低的工资
- SQL> SELECT AVG(sal),ROUND(AVG(sal),2),MAX(sal),MIN(sal) FROM emp;
- 例子:统计出公司最早雇佣和最晚雇佣的雇佣日期
- SELECT MIN(hiredate) , MAX(hiredate) FROM emp ;
- 例子:统计公司工资之中中间的工资值
SELECT MEDIAN(sal) FROM emp ;
- 例子:统计工资的标准差与方差
SELECT STDDEV(sal),VARIANCE(sal) FROM emp ;
二、单字段分组统计(GROUP BY 子句)
利用GROUP BY可以设置分组.
什么时候需要分组?
如果要进行某个字段的分组,那么这个字段列的内容一定会存在重复.
可以直接查看表中全部数据,以确定是否存在可以分组的字段.
分组统计语法:此时SELECT子句中只允许出现“分组字段”和“统计函数”
SELECT [DISTINCT] 分组字段 [AS] [列别名] ,... | 统计函数 [AS] [别名] , …. FROM 表名称1 [表别名1] , 表名称2 [表别名2] …. [WHERE 条件(s)] [GROUP BY 分组字段] [ORDER BY 排序字段 ASC|DESC] ; |
例子:统计每个部门的人数
SELECT deptno,COUNT(*) FROM emp GROUP BY deptno ; |
例子:统计每种职位的最高最低工资
SELECT job, MIN(sal),MAX(sal) FROM emp GROUP BY job; |
SELECT子句在分组操作中的限制(红色字体为错误例子)
没有GROUP BY子句——SELECT子句(统计函数) |
如果没有GROUP BY子句,则在SELECT子句之中只允许出现统计函数,其他任何字段都不允许出现。 SELECT deptno , COUNT(empno) FROM emp ; SELECT COUNT(empno) FROM emp ; |
有GROUP BY子句——SELECT子句(分组字段,统计函数) |
在统计查询之中,SELECT子句后只允许出现分组字段和统计函数,而其他的非分组字段不能使用。 SELECT deptno,ename,COUNT(empno) FROM emp GROUP BY deptno ;(错误的原因是ename不是分组字段) SELECT deptno, COUNT(empno) FROM emp GROUP BY deptno ; |
统计函数嵌套使用——SELECT子句(不能出现任何字段,包括分组字段) |
统计函数允许嵌套使用,但是嵌套统计函数之后的SELECT子句之中不允许再出现任何的字段,包括分组字段。 SELECT deptno,MAX(AVG(sal)) FROM emp GROUP BY deptno ; SELECT MAX(AVG(sal)) FROM emp GROUP BY deptno ; |
例子1:查询每个部门的名称、部门人数、部门平均工资、平均服务年限
- 平均服务年限需要计算年,使用MONTHS_BETWEEN函数
- 分析:
- 确定需要的数据表
- dept表:部门名称
- emp表:部门人数,平均工资,平均服务年限,使用统计函数计算
- 确定已知的关联字段
- 雇员和部门关联:emp.deptno=dept.deptno
dept表和emp表多表查询,暂时不分组 |
SELECT d.dname,e.empno,e.sal,e.hiredate FROM dept d,emp e WHERE e.deptno(+)=d.deptno |
观察dname字段,进行分组: SELECT中只能有分组字段dname和统计函数AVG |
SELECT d.dname, COUNT(e.empno) , AVG(e.sal) avgsal, AVG(MONTHS_BETWEEN(SYSDATE,e.hiredate) / 12)avgyear FROM dept d,emp e WHERE e.deptno(+)=d.deptno GROUP BY d.dname; |
数字处理ROUND |
SELECT d.dname, COUNT(e.empno) , ROUND(AVG(e.sal),2) avgsal, ROUND(AVG(MONTHS_BETWEEN(SYSDATE,e.hiredate) / 12),2) avgyear FROM dept d,emp e WHERE e.deptno(+)=d.deptno GROUP BY d.dname; |
例子2:查询出公司各个工资等级雇员的数量、平均工资
- 分析:
- 确定需要的数据表
- salgrade表:工资等级
- emp表:雇员信息,使用统计函数计算
- sal表:工资信息,使用统计函数平均工资
- 确定已知的关联字段
- 雇员和工资等级关联:emp.sal BETWEEN salgrade.losal AND salgrade.hisal
使用salgrade表和emp关联查询 |
SELECT .s.grade,e.empno,e.sal FROM emp e,salgrade s WHERE e.sal=BETWEEN s.losal AND s.hisal |
观察grade字段,进行分组: SELECT中只能有分组字段grade和统计函数AVG |
SELECT .s.grade,COUNT(e.empno),AVG(e.sal) FROM emp e,salgrade s WHERE e.sal=BETWEEN s.losal AND s.hisal ORDER BY s.grade |
数字处理ROUND |
SELECT s.grade,COUNT(e.empno), ROUND(AVG(e.sal),2) FROM emp e,salgrade s WHERE e.sal BETWEEN s.losal AND s.hisal GROUP BY s.grade ; |
以上两个例子是针对多表查询后的数据进行统计,根据返回结果进行分组,可以说是针对于临时表分组.只要是行列的组成结果一定是临时表
例子3:统计出领取奖金与不领取奖金的雇员的平均工资、平均雇佣年限、雇员人数。
按照常规思路:从结果中可以看到,comm分组会将没有奖金和各种奖金等分为一组
SELECT comm, COUNT(EMPNO),ROUND(AVG(sal),2) avgsal, ROUND(AVG(MONTHS_BETWEEN(SYSDATE,hiredate)/12),2) avgyear FROM emp GROUP BY comm;
COMM COUNT(EMPNO) AVGSAL AVGYEAR
---------- ------------ ---------- ----------
10 2342.5 34.82
1400 1 1250 35.83
500 1 1250 36.43
0 1 1500 35.88
更换思路:如果要实现如上要求就可以分别查询有领取奖金和没有领取奖金的人数,使用UNION连接.
1、找到有领取奖金的雇员平均工资、平均雇佣年限、雇员人数
SELECT '领取奖金', COUNT(EMPNO),ROUND(AVG(sal),2) avgsal, ROUND(AVG(MONTHS_BETWEEN(SYSDATE,hiredate)/12),2) avgyear FROM emp WHERE comm IS NOT NULL;
2、找到不领取奖金的雇员平均工资、平均雇佣年限、雇员人数
SELECT '不领取奖金', COUNT(EMPNO),ROUND(AVG(sal),2) avgsal, ROUND(AVG(MONTHS_BETWEEN(SYSDATE,hiredate)/12),2) avgyear FROM emp WHERE comm IS NULL;
3、联合使用UNION
SELECT '领取奖金', COUNT(EMPNO),ROUND(AVG(sal),2) avgsal, ROUND(AVG(MONTHS_BETWEEN(SYSDATE,hiredate)/12),2) avgyear FROM emp WHERE comm IS NOT NULL
UNION
SELECT '不领取奖金', COUNT(EMPNO),ROUND(AVG(sal),2) avgsal, ROUND(AVG(MONTHS_BETWEEN(SYSDATE,hiredate)/12),2) avgyear FROM emp WHERE comm IS NULL;
'领取奖金' COUNT(EMPNO) AVGSAL AVGYEAR
--------------- ------------ ---------- ----------
不领取奖金 10 2342.5 34.82
领取奖金 3 1333.33 36.05
三、多字段分组(GROUP BY)
多字段分组是GROUP BY定义多个字段,且多个字段必须同时重复。
语法:
SELECT [DISTINCT] 分组字段1 [AS] [列别名] , [分组字段2 [AS] [列别名] , …] | 统计函数 [AS] [别名] , …. FROM 表名称1 [表别名1] , 表名称2 [表别名2] …. [WHERE 条件(s)] [GROUP BY 分组字段1 , 分组字段2 , ….] [ORDER BY 排序字段 ASC|DESC] ; |
例子:现在要求查询出每个部门的详细信息。
分析:部门编号、名称、位置、平均工资、最高工资、部门人数
确定需要的数据表:
emp表:统计平均工资、总工资等
dept表:编号,名称,位置
确定已知道的关联字段:
雇员和部门:emp.deptno=dept.deptno
1、将2张表进行关联,查询部门编号,名称,位置,雇员编号和姓名
SELECT d.deptno,d.dname,d.loc,e.ename,e.empno
FROM emp e,dept d
WHERE e.deptno=d.deptno;
2.现在可以看到三个列的数据整体都在重复,那么就具备了分组的条件,使用多字段分组,显示统计信息.
SELECT d.deptno ,d.dname,d.loc,COUNT(e.empno) count,
ROUND(AVG(sal),2) avg,
SUM(sal) sum, MAX(sal) max, MIN(sal) min
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY d.deptno,d.dname,d.loc;
3.要求列出所有部门,要使用外连接
SELECT d.deptno ,d.dname,d.loc,COUNT(e.empno) count,
ROUND(AVG(sal),2) avg,
SUM(sal) sum, MAX(sal) max, MIN(sal) min
FROM emp e,dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.deptno,d.dname,d.loc;
4、有的部门没有雇员信息,有些结果是null,使用NVL函数处理
SELECT d.deptno ,d.dname,d.loc,NVL(COUNT(e.empno),0) count,
NVL(ROUND(AVG(sal),2) ,0) avg,
NVL(SUM(sal) , 0) sum, NVL(MAX(sal),0) max , NVL(MIN(sal), 0) min
FROM emp e,dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.deptno,d.dname,d.loc;
四、HAVING子句(和WHERE子句的区别)
使用GROUP BY子句可以实现数据的分组显示,但是在很多时候往往需要对分组之后的数据进行再次的过滤,而要想实现这样的功能就只能通过HAVING子句完成。为什么WHERE子句不能实现呢?因为根据各个子句执行的顺序,WHERE在ORDER BY之前就执行了.
WHERE:是在分组前使用, 不能使用统计函数
HAVING:是在分组后使用(必须使用GROUP BY),允许使用统计函数
各个子句的执行顺序:
1、FROM-->
2、WHERE -->
3、GROUP BY(HAVING子句)-->
4、SELECT-->
5、ORDER BY-->
HAVING子句一定要和GROUP BY 子句一起使用
语法:
SELECT [DISTINCT] 分组字段1 [AS] [列别名] , [分组字段2 [AS] [列别名] , …] | 统计函数 [AS] [别名] , …. FROM 表名称1 [表别名1] , 表名称2 [表别名2] …. [WHERE 条件(s)] [GROUP BY 分组字段1 , 分组字段2 , ….] [HAVING 过滤条件(s)] [ORDER BY 排序字段 ASC|DESC] ; |
例子1:查询出所有平均工资大于2000的职位信息、平均工资、雇员人数
SELECT job, ROUND(AVG(sal),2) , COUNT(empno)
FROM emp
GROUP BY job
HAVING AVG(sal)>2000 ;
例子2:列出至少有一个员工的所有部门编号、名称,并统计出这些部门的平均工资、最低工资、最高工资。
分析:
- 确定所需要的数据表
- dept表:部门编号, 名称等
- emp表:统计信息
- 确定已知的关联字段
- 雇员和部门关联:emp.deptno=dept.deptno
1、将两张表关联查询
SELECT d.deptno, d.dname, e.sal,e.empno
FROM emp e, dept d
WHERE e.deptno(+)=d.deptno;
2、分组
SELECT d.deptno, d.dname, d.loc, ROUND(AVG(e.sal),2), MIN(e.sal),MIN(e.sal)
FROM emp e, dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.deptno, d.dname, d.loc;
3、对分组进行排序
SELECT d.deptno, d.dname, d.loc, COUNT(e.empno),ROUND(AVG(e.sal),2), MIN(e.sal),MIN(e.sal)
FROM emp e, dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.deptno, d.dname, d.loc
HAVING COUNT(e.empno)>1;
例子3:显示非销售人员工作名称以及从事同一工作雇员的月工资的总和,并且要满足从事同一工作的雇员的月工资合计大于$5000,输出结果按月工资的合计升序排列
1、显示非销售人员工作名称,从事统一工作雇员的月工资总和
SELECT DISTINCT job,SUM(sal) FROM emp WHERE job<>'SALESMAN' GROUP BY job;
2、满足从事同一工作的雇员,月工资合计大于5000
SELECT DISTINCT job,SUM(sal) FROM emp WHERE job<>'SALESMAN' GROUP BY job HAVING SUM(sal)>5000;
3、将结果排序
SELECT DISTINCT job,SUM(sal) sum FROM emp WHERE job<>'SALESMAN' GROUP BY job HAVING SUM(sal)>5000 ORDER BY sum;
SQL Fundamentals: 分组统计查询(FROM-WHERE-GROUPBY-HAVING-SELECT-ORDER BY)的更多相关文章
- mysql加强(3)~分组(统计)查询
一.分组(统计) 查询 1.语法 : select [distinct] *| 分组字段1[别名] [,分组字段2[别名],...] | 统计函数 from 表名 [别名] [where 条件(s)] ...
- 010.简单查询、分组统计查询、多表连接查询(sql实例)
-------------------------------------day3------------ --添加多行数据:------INSERT [INTO] 表名 [(列的列表)] --SEL ...
- sql 分组统计查询并横纵坐标转换
关于sql 分组统计查询,我们在做报表的时候经常需要用到;今天就在这里整理下; 先附上一段sql代码: if object_id(N'#mytb',N'U') is not null drop tab ...
- Oracle数据库从入门到精通-分组统计查询
视频课程:李兴华 Oracle从入门到精通 视频课程学习者:阳光罗诺 视频来源:51CTO学院 整体内容: 统计函数的使用 分组统计查询的实现 对分组的数据过滤 统计函数 在之前我们就学习过一个COU ...
- SQL Fundamentals || 多表查询(内连接,外连接(LEFT|RIGHT|FULL OUTER JOIN),自身关联,ON,USING,集合运算UNION)
SQL Fundamentals || Oracle SQL语言 一.多表查询基本语法 在进行多表连接查询的时候,由于数据库内部的处理机制,会产生一些“无用”的数据,而这些数据就称为笛卡尔积. 多表查 ...
- sql server 分组统计数据
说明:group by是sql中对数据表中的数据进行分组的,在select列表中出现的字段必须全部出现在group by 字段中,出现在聚合函数中的字段在group by中可有可无,没有出现在sele ...
- MySQL 分组统计查询 表连接(3)
1 查询底薪超过公司平均底薪的员工信息? select e.empno,e.ename,e.salfrom t_emp as e join (select avg(sal) as avg from t ...
- SQL语句--分组统计
一.教师号 星期号 是否有课1 2 有1 3 有2 1 有3 2 有`1 2 有写一条sql语句让你变为这样的表教师号 星期一 星期二 星期三1 2 12 13 1各星期下的数字表示:对应的教师在星期 ...
- rails 各种分组统计查询
SpecialGroup.group(:special_type).countselect special_type,count(*) from special_groups group by spe ...
随机推荐
- 如何打造千万级Feed流系统
from:https://www.cnblogs.com/taozi32/p/9711413.html 在互联网领域,尤其现在的移动互联网时代,Feed流产品是非常常见的,比如我们每天都会用到的朋友圈 ...
- Activiti 5.1.4最佳实践
1.简单介绍 Activiti是一个开源的工作流引擎,它实现了BPMN 2.0规范,可以发布设计好的流程定义,并通过api进行流程调度. Activiti 作为一个遵从 Apache 许可的工作流和业 ...
- jquery easyui datagrid 无滚动条,datagrid 没垂直滚动条
jquery easyui datagrid 无滚动条,datagrid 没垂直滚动条 ============================== 蕃薯耀 2018年2月6日 http://www. ...
- ASPX代码加固小结
1.replace替换 <%@Page Language="C#"%> <% string strID=Request["id"]; strI ...
- 3dmax osg格式导出插件 osgExp OpenSceneGraph Max Exporter
https://sourceforge.net/projects/osgmaxexp/files/OpenSceneGraph%20Max%20Exporter/
- Unity Shader 修改自定义变量的值
Properties { _R(,)) = 1.0 _ColorTex("ColorTex (RGB)", 2D) = "red" {} } SubShader ...
- [原]如何为SqlServer2008数据库分配用户
前言: 当一个项目完成后,为了数据安全,总会对该项目的数据库分配一个用户,应该说总会创建一个用户来管理这个数据库,并且这个用户只能管理这个数据库.搞了好多次,每次都忘记怎么设置,所以写一篇博文记录一下 ...
- mysql分组查询获取组内某字段最大的记录
id sid cid 1 1 12 1 23 2 1 以sid分组,最后取cid最大的那一条,以上要取第2.3条 1 方法一: select * from (select * from table o ...
- css 去除页面双击事件
-ms-touch-action: manipulation !important;
- 一.jquery.datatables.js表格显示
2014年8月10日星期日 使用jquery.datatables.js取后台数据. 1.html代码 <table class="dataTables-example"&g ...