SQL相关语句练习

在之前使用过一个COUNT()函数,此函数的功能是统计表中的数据量,那么在SQL之中,定义了5个常用的统计函数:

  • 统计个数:COUNT(*|[DISTINCT]字段)、
  • MAX(字段)、MIN(字段)、
  • SUM(数字字段)、AVG(数字字段)

范例:查询所有雇员之中最高和最低工资

SELECT MAX(sal),MIN(sal) FROM emp;

  对于MAX()与MIN()的操作除了可以使用数字之外,也可以使用日期。

范例:查询出所有雇员最早雇佣和最晚雇佣的雇佣日期

SELECT MIN(hiredate),MAX(hiredate) FROM emp;

范例:统计出所有雇员的总工资以及平均工资

SELECT SUM(sal),AVG(sal) FROM emp;

  对于SUM()和AVG()函数来说,只要是数值型数据都可以使用。

范例:要求统计出雇员的平均服务年限

SELECT TRUNC(AVG(MONTHS_BETWEEN(SYSDATE,hiredate)/12)) FROM emp;

面试题:请解释COUNT(*)、COUNT(字段)、COUNT(DISTINCT 字段)的区别?

  • COUNT(*):明确的返回表中的数据个数,是最准确的;
  • COUNT(字段):不统计为null的数据个数,如果某一列的数据不可能为null,那么结果与COUNT()相同;
  • COUNT(DISTINCT 字段):统计消除掉重复数据后的数据个数

3.2、分组统计查询

  能够分组的时候往往指的是部分数据不被某些共性。要想分组,使用GROUP BY子句完成。

SELECT [DISTINCT] 分组字段 [别名],... | 统计函数
FROM 表名称[别名]
[WHERE  过滤条件(s)]
[GROUP BY 分组字段,分组字段,分组字段,...]
[ORDER BY 字段 [ASC|DESC]];

范例:要求按照职位分组,统计出每个职位的名称、人数、平均工资

SELECT job,COUNT(*),AVG(sal)
FROM emp
GROUP BY job;

范例:要求查询出每个部门编号,以及每个部门的人数、最高与最低工资

SELECT deptno,COUNT(*),MAX(sal),MIN(sal) 
FROM emp
GROUP BY deptno;

以上实现了分组的操作,但是对于分组操作严格来讲还是存在一些使用上的限制:

  ●限制一:在没有编写GROUP BY子句的时候(全表做为一组),那么SELECT子句之中只允许出现统计函数,不允许出现任何的其他字段;

错误的的代码: 正确的代码:
SELECT COUNT(empno),ename FROM emp; SELECT COUNT(empno) FROM emp;

  ●限制二:在使用GROUP BY子句分组的时候,SELECT子句之中只允许出现分组字段与统计函数,其他字段不允许出现;

错误的代码: 正确的代码:
SELECT job,COUNT(*),ename FROM emp GROUP BY job; SELECT job,COUNT(*) FROM emp GROUP BY job;

  ●限制三:统计函数允许嵌套查询,但是嵌套后的统计查询中,SELECT子句里面不允许再出现任何的字段,包括分组字段,只能够使用嵌套的统计函数。

错误的代码: 正确的代码:
SELECT deptno,MAX(AVG(sal)) FROM emp GROUP BY deptno; SELECT MAX(AVG(sal)) FROM emp GROUP BY deptno;

范例:查询每个部门的名称、人数、平均工资

SELECT d.dname,COUNT(e.empno),AVG(e.sal) 
FROM emp e,dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.dname;

  以上程序最大的特点在于:是针对于一个多表查询的结果进行分组,查询结果由于是行列的组成,所以可以理解为一张临时数据表。

范例:查询出每个部门的编号、名称、位置、部门人数、平均服务年限。

SELECT d.deptno,d.dname,d.loc,COUNT(e.empno),AVG(TRUNC(MONTHS_BETWEEN(SYSDATE,hiredate)/12)) YEAR
FROM emp e,dept d 
WHERE e.deptno(+)=d.deptno 
GROUP BY d.deptno,d.dname,d.loc;

  多字段分组的时候只有多个列的数据完全重复的时候才可以使用。

范例:要求查询出平均工资高于2000的职位名称以及平均工资。

SQL> SELECT AVG(sal) FROM emp WHERE AVG(sal)>2000 GROUP BY job;
SELECT AVG(sal) FROM emp WHERE AVG(sal)>2000 GROUP BY job
                               *
ERROR at line 1:
ORA-00934: group function is not allowed here

  但是运行之后会发现给出的错误提示:WHERE子句上不允许使用分组函数。之所以不能够使用是因为统计的操作属于GROUP BY之后的范畴了,而WHERE是在GROUP BY操作之前使用的,所以此时如果要想针对分组后的数据进行过滤,那么只能够使用HAVING子句。

SELECT [DISTINCT] 分组字段 [别名],... | 统计函数
FROM 表名称[别名]
[WHERE  过滤条件(s)]
[GROUP BY 分组字段,分组字段,分组字段,...]
[HAVING 分组后的过滤条件]
[ORDER BY 字段 [ASC|DESC]];

执行顺序:5,1,2,3,4,6

SELECT job,AVG(sal) 
FROM emp
GROUP BY job
HAVING AVG(sal)>2000;

  

注意:关于WHERE与HAVING的区别?

  ●WHERE发生在GROUP BY操作之前,属于分组前的数据筛选,即:从所有的数据之中筛选出可以分组的数据,WHERE子句不允许使用统计函数;

  ●HAVING发生在GROUP BY操作之后,是针对于分组后的数据进行筛选,HAVING子句可以使用统计函数;

范例:显示非销售人员工作名称以及从事同一工作雇员的月工资的总和,并且要求满足从事同一工作的雇员的月工资合计大于$5000,输出结果按月工资的合计升序排列。

SELECT job,SUM(sal) sum 
FROM emp
WHERE NOT job='SALESMAN'
GROUP BY job
HAVING SUM(sal)>5000
ORDER BY sum;

思考题:统计公司所有领取佣金与不领取佣金的雇员人数、平均工资

SELECT 'GET COMM' title,COUNT(empno),AVG(sal) FROM emp WHERE comm IS NOT NULL
UNION
SELECT 'NO COMM' title,COUNT(empno),AVG(sal) FROM emp WHERE comm IS  NULL;

  在整个分组里面一定要注意,只有在基数固定的时候才可能分组。

4、总结

1、不管是单表分组还是多表分组,重点先看重复的列,如果是一个重复列,那么就在GROUP BY后面写一个字段,如果是多个,就写多个字段;

2、分组中的使用限制:

 ●分组函数嵌套后不能够出现任何字段;

  ●分组函数可以单独使用,如果使用了GROUP BY还可以在SELECT子句里面出现字段;

3、多表查询与分组统计的时候,查询结果相当于是一张临时表,所有的分组是在临时表里完成的。

猜你喜欢

转载自blog.csdn.net/qq_40083102/article/details/79777867