在SELECT 语句中,使用GROUP BY子句进行分组后,如果需要对分组后的数据进行筛选,可以使用HANING子句指定筛选条件。
语法:
select <字段名列表> from <表名>
[where <查询条件>]
group by <分组字段列表>
having <筛选条件>;
HAVING 子句和 WHERE 子句非常相似,都是对数据进行过滤,HAVING 子句支持 WHERE 子句中所有的操作符和语法。
示例:查询各部门clerk的最低工资
mysql> select deptno,job,min(sal) 最低工资
-> from emp
-> where job='clerk'
-> group by deptno,job;
+--------+------------+--------------+
| deptno | job | 最低工资 |
+--------+------------+--------------+
| 10 | clerk | 1300 |
| 20 | clerk | 800 |
| 30 | clerk | 950 |
+--------+------------+--------------+
mysql> select deptno,job,min(sal) 最低工资
-> from emp
-> group by deptno,job
-> having job='clerk';
+--------+------------+--------------+
| deptno | job | 最低工资 |
+--------+------------+--------------+
| 10 | clerk | 1300 |
| 20 | clerk | 800 |
| 30 | clerk | 950 |
+--------+------------+--------------+
WHERE与HAVING的区别:
- WHERE 子句主要用于过滤数据行,而 HAVING 子句主要用于过滤分组。
- WHERE 子句不可以包含聚合函数,HAVING 子句中的条件可以包含聚合函数。
- HAVING 子句是在数据分组后进行过滤,WHERE 子句会在数据分组前进行过滤,WHERE 子句排除的行不包含在分组中。
示例:查询各部门平均工资大于3000的职位
mysql> select deptno,job,avg(sal)
-> from emp
-> where avg(sal)>3000
-> group by deptno,job;
ERROR 1111 (HY000): Invalid use of group function
mysql> select deptno,job,avg(sal)
-> from emp
-> group by deptno,job
-> having avg(sal)>3000;
+--------+-----------+----------+
| deptno | job | avg(sal) |
+--------+-----------+----------+
| 10 | persident | 5000 |
+--------+-----------+----------+
SQL语句的执行顺序:
FROM -> ON -> JOIN -> WHERE -> GROUP BY -> HAVING -> SELECT -> DISTINCT -> UNION -> ORDER BY -> LIMIT
WHERE在分组和聚集计算之前筛选行,而HAVING 在分组和聚集之后筛选分组的行,因此WHERE子句不能包含聚集函数。
而HAVING 子句是在SELECT子句前执行,因此一般不能在HAVING 子句中使用select定义的别名。但是MySQL对此作了扩展。在mysql 5.7.5之前的版本,ONLY_FULL_GROUP_BY sql mode默认不开启。在5.7.5或之后的版本默认开启。
如果ONLY_FULL_GROUP_BY sql mode不开启,那么mysql对标准SQL的扩展可以生效:
- 允许在select、having和order by中使用没有出现在group by中的字段。此时mysql会随机选择没有出现在group by中的字段的值。
- 允许在having中使用select定义的别名。
HAVING 子句中的筛选字段必须在SELECT子句中出现:查询各部门manager的平均工资
mysql> select deptno,avg(sal) 平均工资
-> from emp
-> group by deptno
-> having job='manager';
ERROR 1054 (42S22): Unknown column 'job' in 'having clause'
mysql> select deptno,job,avg(sal) 平均工资
-> from emp
-> group by deptno,job
-> having job='manager';
+--------+------------+--------------+
| deptno | job | 平均工资 |
+--------+------------+--------------+
| 10 | manager | 2450 |
| 20 | manager | 2975 |
| 30 | manager | 2850 |
+--------+------------+--------------+