1. 前言
在 MySQL 中使用 select 查询语句的时候,一般都会加上 where 语句或者 limit 语句限定查询结果的范围,两种子句都是过滤的作用。另外还有和 group by 语句配合使用的 having 限制条件。区分 where 和 having 语句的作用也是比较基础的题目。
2. where 和 having
面试官提问: 请阐述下在 MySQL 中 where 和 having 关键词有什么区别?
题目解析: 为了更加清楚地阐述两个关键用法的不同,我们还是从实际例子出发。
进入上一节创建的测试数据库:
USE mybj_demo;
然后进入测试数据库,创建 user 表:
USE `mybj_demo`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '数据库主键',
`username` varchar(32) DEFAULT NULL COMMENT '用户名',
`password` varchar(32) DEFAULT NULL COMMENT '密码',
`gender` int(2) DEFAULT NULL COMMENT '1:男性,2:女性',
`age` int(10) DEFAULT NULL COMMENT '年龄',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
然后再插入一些测试数据:
insert into user (username,password,gender,age) values ('小明','123456',1,20);
insert into user (username,password,gender,age) values ('小红','123457',2,22);
insert into user (username,password,gender,age) values ('小王','123458',1,24);
insert into user (username,password,gender,age) values ('小刘','123459',2,26);
2.1 where 和 having 都能使用的场景
select username,password,gender,age from user where age >= 20;
select username,password,gender,age from user having age >= 20;
上述两条 sql 都能执行成功,如果 select 之后的字段包含 having 修饰的字段,这种情况下 where 和 having 是等效的。
2.2 只能用 where,不能用 having 的场景
select username,password,gender from user where age >= 20;
select username,password,gender from user having age >= 20;
第一条 sql 执行成功,执行第二条 sql 会报错:ERROR 1054 (42S22): Unknown column 'age' in 'having clause'
,翻译过来就是 "对于 having 语句,age 字段是未知的"。
having 执行的前置条件是:select xxx,...
筛选出的字段包含 having 修饰的关键词。
两者的执行顺序不同:因为 having 是从前面筛选出来的字段中再进行二次筛选,where 则是针对全表先进行筛选。
2.3 只能用 having,不能用 where 的场景
select count(*),gender,avg(age) as avg_age from user group by gender where avg_age > 20;
select count(*),gender,avg(age) as avg_age from user group by gender having avg_age > 20;
我们的目的是 "按照性别进行分组,统计平均年龄大于 20 的人数、性别和平均年龄"。
但是第一条 sql 执行会报错:ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where avg_age > 20' at line 1
,即对于 where 语句,全表并没有 avg_age
平均年龄这个字段,所以会搜索失败。
从上述的实验结果总结来看,where 和 having 的核心区别有三点:
① 使用范围的不同:
- where:能够用于 select、update、delete 语句;
- having:只能用于 select 查询语句。
② 执行顺序不同:
- where 修饰的搜索条件是在分组完成之前执行;
- having 修饰的搜索条件是在分组完成之后执行。如果一条 sql 语句同时包含 where 和 having 关键词,会先执行 where 搜索,再执行 having 搜索条件。
③ 聚合函数的联合使用:
- where:不能联合聚合函数(sum、avg、count、max、min 这类)使用;
- having:能够联合聚合函数使用。
3. 小结
本章节介绍了 where 和 having 语句的用法和不同点,候选人在阐述的时候需要抓住最核心的一点,where 语句在聚合之前筛选数据,having 语句在聚合之后对数据进行筛选,作用在 group by 语句之后。