数据库的统计查询
掌握一些统计函数的使用,能更方便我们查询数据。
统计函数
- COUNT():求出全部的记录数
- SUM():求出总和,操作的列是数字
- AVG():平均值
- MAX():最大值
- MIN():最小值
- MEDIAN():返回中间值
- VARIANCE():返回方差
- STDDEV():返回标准差
从SQL标准规定来讲,实际上只有前5个是标准函数。
范例:
查询出公司每个月支出的月工资总和
SELECT SUM(sal) FROM emp;
查询出公司的最高工资、最低工资、平均工资
SELECT MAX(sal), MIN(sal), AVG(sal), ROUND(AVG(sal),2) FROM emp;
其中ROUND()表示的是取两位小数
统计出公司的雇员人数
SELECT COUNT(*), COUNT(empno), COUNT(DISTINCT job) FROM emp;
注:对于COUNT()函数而言,可以传递三类内容:*、字段、DISTICT 字段;而且在所有统计函数当中,只有COUNT()函数可以在表中没有任何数据的时候依然返回内容,即返回0,其他则返回null。
面试题:
题目:请问COUNT(*), COUNT(字段), COUNT(DISTINCT 字段)有什么区别?
答案:在使用COUNT(字段)的时候,如果列上存在了null,那么null是不会进行统计的,如果存在重复,重复的记录也不统计。
GROUP BY分组
是否能进行分组:判断表中是否有一列或多列数据重复
子句的执行顺序:FROM、WHERE、GROUP BY、SELECT、ORDER BY
分组统计简单范例:
统计出每个部门的人数
分析:此时一定需要按照部门的信息分组,在emp表中,每个雇员的部门都使用一个部门编号表示。那么就可以针对deptno字段来实现分组。
1
2
3SELECT deptno, COUNT(*)
FROM emp
GROUP BY deptno;
分组的若干个限制:
- 注意事项一:如果在一个查询之中不存在GROUP BY子句,那么SELECT子句只允许出现统计函数,其他的任何字段都不允许出现
- 注意事项二:在统计查询之中(存在了GROUP BY子句),SELECT子句之中只允许出现分组字段(GROUP BY之后定义的字段)和统计函数,其他的任何字段都不允许出现
注意事项三:所有统计函数允许嵌套使用,但是一旦使用了嵌套的统计函数之后,SELECT子句之中不允许再出现任何的字段,包括分组字段
注意事项三的范例:求出每个部门平均工资的最高工资
1
2
3SELECT MAX(AVG(sal))
FROM emp
GROUP BY deptno;
分组统计复杂范例:
查询每个部门的名称、部门人数、部门平均工资、平均服务年限
步骤一:将dept表和emp表一起进行查询,暂时不分组 – 查询每个部门的名称、雇员编号、工资、雇佣日期
1
2
3SELECT d.dname, e.empno, e.sal, e.hiredate
FROM dept d, emp e
WHERE e.deptno = d.deptno;步骤二:观察现在的dname字段(查询结果,理解为临时表),既然有重复的列就可以进行分组,针对于临时表数据进行分组
1
2
3
4
5
6SELECT d.dname, COUNT(e.empno),
ROUND(AVG(e.sal), 2),
ROUND(AVG(MONTHS_BETWEEN(SYSDATW,e.hiredate)/12),2)
FROM dept d, emp e
WHERE e.deptno = d.deptno
GROUP BY d.dname;步骤三:针对部门信息是包含四个部门信息,可是上面结果只有三个部门的信息,因此需要加入外连接显示第四个部门的统计
1
2
3
4
5
6SELECT d.dname, COUNT(e.empno),
ROUND(AVG(e.sal), 2),
ROUND(AVG(MONTHS_BETWEEN(SYSDATW,e.hiredate)/12),2)
FROM dept d, emp e
WHERE e.deptno(+) = d.deptno
GROUP BY d.dname;
多字段分组
范例:
查询出每个部门的详细信息
分析:
一定要包含的是:部门编号、名称、位置、平均工资、总工资、最高工资、最低工资、部门人数
肯定不止一张表
步骤:
步骤一:将题目要求转换、将emp表和dept表关联,查询出部门编号、名称、位置、雇员编号、姓名
1
2
3SELECT d.deptno, d.dname, d.loc, e.empno, e.ename
FROM emp e, dept d
WHERE e.deptno = d.deptno;步骤二:使用多字段分组(此处有三个地方重复)
1
2
3
4SELECT d.deptno, d.dname, d.loc, COUNT(e.empno), ROUND(AVG(e.sal),2), SUM(e.sal), MAX(e.sal), MIN(e.sal)
FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY d.deptno, d.dname, d.loc;步骤三:使用外连接,因为此处部门信息不全
1
2
3
4SELECT d.deptno, d.dname, d.loc, COUNT(e.empno), ROUND(AVG(e.sal),2), SUM(e.sal), MAX(e.sal), MIN(e.sal)
FROM emp e, dept d
WHERE e.deptno(+) = d.deptno
GROUP BY d.deptno, d.dname, d.loc;步骤四:NVL处理,是null结果为0
1
2
3
4SELECT d.deptno, d.dname, d.loc, COUNT(e.empno), NVL(ROUND(AVG(e.sal),2),0), NVL(SUM(e.sal),0), NVL(MAX(e.sal),0), NVL(MIN(e.sal),0)
FROM emp e, dept d
WHERE e.deptno(+) = d.deptno
GROUP BY d.deptno, d.dname, d.loc;
HAVING子句
目的:对分组子句进行过滤。(使用WHERE是不行的,因为WHERE执行顺序在GROUP BY之前)
HAVING子句必须和GROUP BY子句一起使用
子句的执行顺序:FROM、WHERE、GROUP BY、HAVING、SELECT、ORDER BY
范例:
查询出所以平均工资大于2000的职位信息、平均工资、雇员人数
1
2
3
4SELECT job, ROUND(AVG(sal),2), COUNT(empno)
FROM emp
GROUP BY job
HAVING AVG(sal) > 2000;列出至少有一个员工的所有部门编号、名称,并统计出这些部门的平均工资、最低工资、最高工资
1
2
3
4
5SELECT d.deptno, d.name, ROUND(AVG(sal),2),MIN(e.sal), MAX(e.sal)
FROM emp e, dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.deptno, d.dname
HAVING COUNT(e.empno)>1;