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 ...
随机推荐
- MVC5 Entity Framework学习之实现主要的CRUD功能
在上一篇文章中,我们使用Entity Framework 和SQL Server LocalDB创建了一个MVC应用程序,并使用它来存储和显示数据.在这篇文章中,你将对由 MVC框架自己主动创建的CR ...
- 8 -- 深入使用Spring -- 7... Spring 整合 Struts 2
8.7 Spring 整合 Struts2 8.7.1 启动Spring 容器 8.7.2 MVC框架与Spring整合的思考 8.7.3 让Spring管理控制器 8.7.4 使用自动装配
- mac开机启动apache、memcached与mysql
一.开机自动启动apache方法 #sudo launchctl load -w /System/Library/LaunchDaemons/org.apache.httpd.plist //开机启动 ...
- 我的notepad++
我觉得,做开发的一定要有一个简单,但功能强大的文本编辑器.我比较喜欢notepad++,而且一直使用.准备通过这篇文章分享一下我的notepad++配置. 希望广大notepad++用户,如果有好的配 ...
- 解决win10休眠后无法唤醒
在控制面板-电源选项-编辑计划设置-高级电源设置中把"睡眠"的选项中休眠调整为从不,"电源按键和盖子"选项中也都设为睡眠,这样使得无论你是使用电池还是电源,系统 ...
- C语言对文件的基本操作
在C语言中,对于文件的操作是利用FILE结构体进行的. 几个常用的操作文件函数简介 1:打开文件 FILE *fopen( const char *filename, const char *mode ...
- Docker应用之镜像
一.Docker包括三个基本概念 1.镜像(Image):Docker镜像是一个只读模板,例如一个镜像可以包含完整的Linux系统环境,里面仅仅安装了Apache或用户其他应用程序:镜像可以用来创建D ...
- ubuntu11.10 64bit 编译android 4.0
前言: 据说google内部使用的的ubuntu版本始终是10.4, 而我一直使用的编译2.3Gingerbread的 11.04下补充安装uuid-dev和liblzo2-dev两个库就可以直接编译 ...
- 不作死就不会死,微软强行插入NO-IP
微软啊微软,你这是何苦来着. 事情经过大致是这样的,微软向美国法院提出起诉No-IP名下22个常用的子域名被恶意软件的作者滥用,要求法官裁定由微软接管No-IP名下的这22个子域名,以便其可以过滤恶意 ...
- STL——仿函数(函数对象)
一.仿函数(也叫函数对象)概观 仿函数的作用主要在哪里?从第6章可以看出,STL所提供的各种算法,往往有两个版本,其中一个版本表现出最常用(或最直观)的某种运算,第二个版本则表现出最泛化的演算流程,允 ...