DQL语句之分组与过滤

DQL语句之分组与过滤


说明:以下将使用mysql数据库管理系统中的mysql数据库中的emp表作为例子

本次内容接上次的学习笔记:
SQL中的DQL语句二(学习笔记三)

一、分组函数

分组函数又叫多行处理函数,多行处理函数只有5个;
avg 求平均
max 求最大值
min 求最小值
count 求一列有几个数
sum 求和
有以下几个特点:

1.所有的分组函数都是对"某一组"数据进行操作的且输入多行,最终输出的结果为一行

例:求出工资的最大值

select max(sal) from emp;

输出结果:

+----------+
| max(sal) |
+----------+
|  5000.00 |
+----------+

例:

select ename,max(sal) from emp;

输出结果:

ERROR 1140 (42000): In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'mysql.emp.ENAME'; this is incompatible with sql_mode=only_full_group_by

2.多行处理函数自动忽略空(null)

所有数据库都是这样规定的,只要有NULL参与的运算结果一定是NULL

emp的表是这样的:

+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME  | JOB       | MGR  | HIREDATE   | SAL     | COMM    | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800.00 |    NULL |     20 |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1600.00 |  300.00 |     30 |
|  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1250.00 |  500.00 |     30 |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2975.00 |    NULL |     20 |
|  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1250.00 | 1400.00 |     30 |
|  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 2850.00 |    NULL |     30 |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450.00 |    NULL |     10 |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000.00 |    NULL |     20 |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000.00 |    NULL |     10 |
|  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500.00 |    0.00 |     30 |
|  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100.00 |    NULL |     20 |
|  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 |  950.00 |    NULL |     30 |
|  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000.00 |    NULL |     20 |
|  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300.00 |    NULL |     10 |
+-------+--------+-----------+------+------------+---------+---------+--------+

comm(补贴,福利)中的null是比较多的,我们以comm为例:
比如说,给每个员工涨10元补贴

select ename,(comm+10) as comm  from emp;

输出结果:

+--------+---------+
| ename  | comm    |
+--------+---------+
| SMITH  |    NULL |
| ALLEN  |  310.00 |
| WARD   |  510.00 |
| JONES  |    NULL |
| MARTIN | 1410.00 |
| BLAKE  |    NULL |
| CLARK  |    NULL |
| SCOTT  |    NULL |
| KING   |    NULL |
| TURNER |   10.00 |
| ADAMS  |    NULL |
| JAMES  |    NULL |
| FORD   |    NULL |
| MILLER |    NULL |
+--------+---------+

可以看到,所有带NULL的 加上10后都没有变化,这个非常直观的说明了只要有NULL参与的运算结果一定是NULL

求出comm的平均值;

select avg(comm) from emp;

输出结果

+------------+
| avg(comm)  |
+------------+
| 550.000000 |
+------------+

这个例子也非常直观的说明了多行处理函数自动忽略空(NULL)

:这里特别说明一下,因为多行处理函数是自动忽略NULL的,所以,一定不要这样写:

select sum(comm) from emp where comm is not null;

在使用多行处理行数时,不要在后面加where xxxx is not null
程序不会报错,但是画蛇添足,可以写但是完全没有必要。

3.分组函数一般都会和group by联合使用,这也是为什么它被称为分组函数的原因。

任何一个分组函数(count sum avg max min)都是在group by语句执行结束之后才会执行的。

没有写group by 相当于java的缺省一样,是会存在的,以整个表为一组。group by下面会讲。

说明:1.count (*)和count (具体的某个字段),他们有什么区别?

count(*) :不是统计某个字段中数据的个数,而是统计总记录条数。(和某个字段无关)
count(具体的某个字段):表示统计具体的某个字段中不为NULL的数据总数量。

小tips:分组函数也能组合起来用

select count(*) , sum(sal) ,avg(sal) ,max (sal) ,min(sal) from emp;

单行处理函数

单行处理函数比较多,如果在这里一一赘述就会显得这篇博文太长了,这里只举个例子。
这里放一个其他人的博文链接:
MySQL学习笔记(2)–数据处理函数/单行处理函数

单行处理函数的特点与多行处理函数不同,它是输入一行,输出一行。
回顾一下这个:所有数据库都是这样规定的,只要有NULL参与的运算结果一定是NULL

那举个例子:求出所有员工的年薪:
因为上面这个原因,我们不能直接求出来,所以,这个时候引出我们的新函数 ifnull()空处理函数

ifnull是用法是:
ifnull(可能为NULL的数据,被当做什么处理)

那我们就可以这样写:

select ename,(sal+ifnull(comm,0))*12 from emp;

输出结果:

+--------+-------------------------+
| ename  | (sal+ifnull(comm,0))*12 |
+--------+-------------------------+
| SMITH  |                 9600.00 |
| ALLEN  |                22800.00 |
| WARD   |                21000.00 |
| JONES  |                35700.00 |
| MARTIN |                31800.00 |
| BLAKE  |                34200.00 |
| CLARK  |                29400.00 |
| SCOTT  |                36000.00 |
| KING   |                60000.00 |
| TURNER |                18000.00 |
| ADAMS  |                13200.00 |
| JAMES  |                11400.00 |
| FORD   |                36000.00 |
| MILLER |                15600.00 |
+--------+-------------------------+

二、group by(分组查询)与having(过滤)

group by:按照某个字段或者某些字段进行分组。
having:having是对分组之后的数据进行再次过滤

重点:关于SQL语句的执行顺序问题

select    5
...
from      1
...
where     2
....
group by  3 
....
having    4
....
order by  6
...



注:分组函数是在group by之后执行
没有写group by 时,实际上相当于默认存在,以整个表作为一个组

这个时候,就会出现一些问题,比如说这样:
选出大于平均工资的员工:

select ename,sal from emp where sal > avg(sal);

就会报错:
ERROR 1111 (HY000): Invalid use of group function

正确的写法应该是:

select ename,sal from emp where sal > (select avg(sal) from emp);

或者,求出平均工资后,再将平均工资代入where sal > xxx中。

注:注意这个书写顺序与执行顺序,很容易搞错。
还有除了select from 是必须写的外的,其他应该根据需求进行组合。

1.group by 的用法

group by:按照某个字段或者某些字段进行分组。
注意:分组函数一般都会和group by联合使用,这也是为什么它被称为分组函数的原因。
并且任何一个分组函数(count sum avg max min)都是在group by语句执行结束之后才会执行的。

案例:找出每个工作岗位的最高薪资。

select max(sal),job from emp group by job;


输出结果:
+----------+-----------+
| max(sal) | job       |
+----------+-----------+
|  1300.00 | CLERK     |
|  1600.00 | SALESMAN  |
|  2975.00 | MANAGER   |
|  3000.00 | ANALYST   |
|  5000.00 | PRESIDENT |
+----------+-----------+

那能不能找出这些工资对应的人呢?

select ename,max(sal),job from emp group by job;

ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'mysql.emp.ENAME' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

是不行的

注意:当一条语句中有group by的话,select后面只能跟分组函数和参与分组的字段。

多字段分组查询

这是一个比较重要的点,一般来说,把需求拆分,理清思路,并不是很难.
举例:
找出每个部门不同工作岗位的最高薪资。

在这里我们就要将需求拆解,理清思路。

首先,我们还是要参照一下,前面的执行顺序。在这里我在放过来。

select    5
...
from      1
...
where     2
....
group by  3 
....
having    4
....
order by  6

注:分组函数是在group by之后执行

先where 进行筛选,然后是group by 进行分组,其次可以对过滤分组后的表再次进行筛选,最后进行排序。

那么,这个东西就好写了。

找出每个部门不同工作岗位的最高薪资。

首先,我们可以先分组,这里需要对两种数据进行分组,第一个是部分,第二个是工作岗位。

select job,deptno from emp group by deptno,job;

然后再找出每个部门不同工作岗位的最高薪资。

select job,deptno,max(sal) from emp group by deptno,job order by deptno;
+-----------+--------+----------+
| job       | deptno | max(sal) |
+-----------+--------+----------+
| CLERK     |     10 |  1300.00 |
| MANAGER   |     10 |  2450.00 |
| PRESIDENT |     10 |  5000.00 |
| ANALYST   |     20 |  3000.00 |
| CLERK     |     20 |  1100.00 |
| MANAGER   |     20 |  2975.00 |
| CLERK     |     30 |   950.00 |
| MANAGER   |     30 |  2850.00 |
| SALESMAN  |     30 |  1600.00 |
+-----------+--------+----------+

having 与 where

having 和 where 两者的作用都是对表进行筛选,两者的区别在于 where 在group by 之前, having 在group by 之后。也就是说,
当需要在分组前进行筛选时,使用where;
当需要在分组后筛选时,选择having;
当无论分组前筛选,还是分组后筛选没有区别时,选择 having 与 选择 where 的最终结果是没有区别的。

这里建议此时选择使用 where ,因为当你筛选过后,group by 进行分组需要操作的量就小了。

这里来几个例子:

使用where 与使用 having 没有区别的。

找出每个部门的最高薪资,要求显示薪资大于 2900 的数据。
这里就可以有两种写法。

 select max(sal),deptno from emp group by deptno having max(sal) > 2900;
 
select max(sal),deptno from emp where sal > 2900 group by deptno;

必须要使用 having的

例:
找出每个部门的平均薪资,要求显示薪资大于2000的数据。

  select deptno,avg(sal) from emp group by deptno having avg(sal) > 2000;
上一篇:MySQL——子查询,分页查询


下一篇:MySQL——初学MySQL