mysql中 where与having的区别

本文详细解析了SQL中where与having子句的区别,包括执行顺序、功能特性及使用场景,帮助理解聚合函数与条件筛选的关系。

mysql中 where与having的区别

having子句与where有相似之处但也有区别,都是设定条件的语句。
在查询过程中聚合语句(sum,min,max,avg,count)要比having子句优先执行.而where子句在查询过程中执行优先级别优先于聚合语句(sum,min,max,avg,count)。

1即执行优先级别:where > 聚合函数 > having

简单说来:
where子句:
select sum(num) as rmb from order where id>10
//只有先查询出id大于10的记录才能进行聚合语句

having子句:
select reportsto as manager, count() as reports from employees
group by reportsto having count(
) > 4
以northwind库为例.having条件表达示为聚合语句。肯定的说having子句查询过程执行优先级别低于聚合语句。
再换句说话说把上面的having换成where则会出错。统计分组数据时用到聚合语句。
对分组数据再次判断时要用having。如果不用这些关系就不存在使用having。直接使用where就行了。

having就是来弥补where在分组数据判断时的不足。因为where执行优先级别要快于聚合语句。

聚合函数,这是必需先讲的一种特殊的函数:
例如SUM, COUNT, MAX, AVG等。这些函数和其它函数的根本区别就是它们一般作用在多条记录上。
SELECT SUM(population) FROM tablename

这里的SUM作用在所有返回记录的population字段上,结果就是该查询只返回一个结果,即所有
国家的总人口数。 通过使用GROUP BY 子句,可以让SUM 和 COUNT 这些函数对属于一组的数据起作用。
当你指定 GROUP BY region 时, 属于同一个region(地区)的一组数据将只能返回一行值.
也就是说,表中所有除region(地区)外的字段,只能通过 SUM, COUNT等聚合函数运算后返回一个值.
HAVING子句可以让我们筛选成组后的各组数据.
HAVING子句在聚合后对组记录进行筛选
而WHERE子句在聚合前先筛选记录.也就是说作用在GROUP BY 子句和HAVING子句前

看下面这几个例子吧:

一、显示每个地区的总人口数和总面积.
SELECT region, SUM(population), SUM(area)
FROM bbc
GROUP BY region
先以region把返回记录分成多个组,这就是GROUP BY的字面含义。分完组后,然后用聚合函数对每组中的不同字段(一或多条记录)作运算。

二、 显示每个地区的总人口数和总面积.仅显示那些面积超过1000000的地区。
SELECT region, SUM(population), SUM(area)
FROM bbc
GROUP BY region
HAVING SUM(area)>1000000
在这里,我们不能用where来筛选超过1000000的地区,因为表中不存在这样一条记录。
相反,HAVING子句可以让我们筛选成组后的各组数据.

以下示例使用的数据库是MySQL 5。
数据表:student
表结构:
Field Name DataType Len
id int 20
name varchar 25
major varchar 25
score int 20
sex varchar 20

表数据:
编号/姓名/专业/学分/性别
id name major score sex
1 jak Chinese 40 f
2 rain Math 89 m
3 leo Phy 78 f
4 jak Math 76 f
5 rain Chinese 56 m
6 leo Math 97 f
7 jak Phy 45 f
8 jak Draw 87 f
9 leo Chinese 45 f

现在我们要得到一个视图:
要求查询性别为男生,并且列出每个学生的总成绩:
SQL:
select s.*,sum(s.score) from student s where sex=‘f’ group by s.name

Result:
id name major score sex sum(s.score)
1 jak Chinese 40 f 248
3 leo Phy 78 f 220

可以看到总共查到有两组,两组的学生分别是jak和leo,每一组都是同一个学生,这样我们就可以使用聚合函数了。
只有使用了group by语句,才能使用如:count()、sum()之类的聚合函数。

下面我们再对上面的结果做进一步的筛选,只显示总分数大于230的学生:
SQL:
select s.*,sum(s.score) from student s where sex=‘f’ group by s.name having sum(s.score)>230

Result:
id name major score sex sum(s.score)
1 jak Chinese 40 f 248

可见having于where的功能差不多。

结论:

1.WHERE 子句用来筛选 FROM 子句中指定的操作所产生的行。

2.GROUP BY 子句用来分组 WHERE 子句的输出。

3.HAVING 子句用来从分组的结果中筛选行。

where 在聚合之前过滤

当一个查询包含了聚合函数及where条件,像这样的情况

select max(cid) from t where t.id<999

这时候会先进行过滤,然后再聚合。先过滤出ID《999的记录,再查找最大的cid返回。

having 在聚合之后过滤

having在分组的时候会使用,对分组结果进行过滤,通常里面包含聚合函数。

SELECT ip,MAX(id) FROM app
GROUP BY ip
HAVING MAX(id)>=5

先分组,再聚合,然后过滤聚合结果大于等于5的结果集

二者的区别:

where是先执行,然后再执行聚合函数。having是在聚合函数执行完之后再执行。

where与having的区别:

1.where是数据从磁盘读入内存的时候进行判断, 而having是磁盘读入内存后再判断。

Alt
上面截图使用having的情况,数据库就会先将所有的数据先读入内存,然后才会在内存中判断条件是否符合,不符合条件的数据会被删除。
Alt
像上面截图这种使用where的情况,就是先从磁盘读取数据如果数据的email = ‘0177@gmx.de’,那么这条数据就放人内存中,如果email不等于0177@gmx.de那么就直接忽略这条数据。

2.where不可以使用字段的别名,但是having可以。

因为where是先判断数据是否符合条件,符合条件的数据再入内存中然后生成别名,所以别名是where判断条件后才生成的,这 也是where不能使用别名的原因。

having是先从磁盘中读取数据到内存中,然后才进行判断,这个时候别名已经生成了,所以having可以使用别名。

3.having能够使用聚合函数当做条件,但是where不能使用,where只能使用存在的列当做条件。

原因与区别二一样。

总结,能用where就用where,使用where比用having效率要高很多,这里有一个误区:就是不要错误的认为having和group by 必须配合使用

<think>我们正在讨论MySQLHAVINGWHERE子句区别。根据提供的引用信息,我们可以总结出以下几点关键区别: 1. **执行顺序不同**:WHERE子句在数据从磁盘读入内存时进行过滤(在GROUP BY之前),而HAVING子句在分组(GROUP BY)之后对分组结果进行过滤[^3][^4]。 2. **使用场景不同**:WHERE用于过滤原始数据表中的行,而HAVING用于过滤分组后的结果集(即GROUP BY配合使用)[^1][^3]。 3. **能否使用聚合函数**:WHERE子句中不能使用聚合函数(如SUM, AVG, COUNT等),而HAVING子句可以[^1][^3][^5]。 4. **能否使用别名**:WHERE子句中不能使用SELECT中定义的列别名,而HAVING子句可以[^3]。 5. **效率考虑**:由于WHERE在分组前过滤数据,通常比HAVING更高效,因为HAVING是在分组后对大量分组结果进行过滤。因此,应尽可能使用WHERE提前过滤数据[^3]。 下面我们通过示例来进一步说明: ### 示例1:WHEREHAVING的基本使用 假设有一个员工表(employees),包含字段:id, name, department, salary。 **使用WHERE过滤行**: ```sql SELECT * FROM employees WHERE salary > 5000; ``` 这条语句在分组前过滤出工资大于5000的员工。 **使用HAVING过滤分组**: ```sql SELECT department, AVG(salary) as avg_salary FROM employees GROUP BY department HAVING avg_salary > 6000; ``` 这里先按部门分组,计算每个部门的平均工资,然后过滤出平均工资大于6000的部门。 ### 示例2:WHEREHAVING的执行顺序 考虑以下查询: ```sql SELECT department, COUNT(*) as emp_count FROM employees WHERE salary > 3000 GROUP BY department HAVING emp_count > 5; ``` 执行顺序: 1. 先用WHERE过滤出工资大于3000的员工(此时还没有分组)。 2. 然后按部门分组(GROUP BY)。 3. 最后用HAVING过滤出员工数量大于5的部门。 ### 示例3:聚合函数在HAVING中的使用 ```sql SELECT department, MAX(salary) as max_salary FROM employees GROUP BY department HAVING MAX(salary) > 10000; ``` 注意:这里HAVING条件中直接使用了聚合函数`MAX(salary)`,这在WHERE子句中是不允许的。 ### 示例4:别名在HAVING中的使用 ```sql SELECT department, AVG(salary) as avg_salary FROM employees GROUP BY department HAVING avg_salary > 6000; -- 这里使用了别名avg_salary ``` 而在WHERE子句中不能使用别名,因为别名是在SELECT中定义的,而WHERE的执行在SELECT之前(根据执行顺序)。 ### 总结对比表 | 特性 | WHERE子句 | HAVING子句 | |--------------|-------------------------------|--------------------------------| | 执行顺序 | 在GROUP BY之前,数据读入内存时 | 在GROUP BY之后 | | 是否使用聚合函数 | 不可以 | 可以 | | 是否使用别名 | 不可以(因为执行顺序在SELECT前) | 可以(执行顺序在SELECT后) | | 使用场景 | 过滤原始数据行 | 过滤分组后的结果集 | | 效率 | 通常更高(提前过滤减少数据量) | 相对较低(在分组后过滤) | ### 建议 - 当过滤条件不依赖于分组时,优先使用WHERE,因为它可以减少分组操作的数据量,提高效率。 - 当过滤条件依赖于分组结果(如使用聚合函数)时,必须使用HAVING。 §§相关问题§§ 1. 在MySQL中,WHEREHAVING子句可以同时使用吗?如果可以,执行顺序是怎样的? 2. 为什么HAVING子句可以使用聚合函数而WHERE不能? 3. 能否举例说明在同一个查询中同时使用WHEREHAVING? 4. 在编写SQL时,如何优化同时使用WHEREHAVING的查询?</think>### MySQLHAVINGWHERE区别详解 在MySQL中,`WHERE``HAVING`都是用于数据过滤的子句,但它们的应用场景执行逻辑有本质区别。以下是核心差异总结: | 特性 | WHERE子句 | HAVING子句 | |--------------|-------------------------------|--------------------------------| | **执行阶段** | 数据从磁盘加载到内存时 | GROUP BY分组之后 | | **作用对象** | 原始数据行 | 分组后的结果集 | | **聚合函数** | 不可使用(如COUNT/SUM) | 可使用(如`HAVING COUNT(*) > 5`) | | **列别名** | 不可引用SELECT中的别名 | 可引用SELECT中的别名 | | **执行顺序** | 在GROUP BY之前(优先级更高) | 在GROUP BY之后 | | **效率** | 优先使用(减少分组数据量) | 分组后过滤(效率较低) | #### 一、核心区别详解 1. **执行顺序不同** SQL标准执行顺序: `FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT` - `WHERE`在数据分组前过滤(磁盘→内存阶段)[^3][^4] - `HAVING`在分组后对聚合结果过滤[^1][^5] 2. **聚合函数支持** ```sql -- 错误:WHERE不能使用聚合函数 SELECT department, AVG(salary) FROM employees WHERE AVG(salary) > 5000; -- ❌ 报错! -- 正确:HAVING支持聚合函数 SELECT department, AVG(salary) AS avg_sal FROM employees GROUP BY department HAVING AVG(salary) > 5000; -- ✅ ``` 3. **别名使用差异** ```sql -- 错误:WHERE不能引用别名 SELECT name AS employee_name FROM employees WHERE employee_name LIKE 'A%'; -- ❌ 报错! -- 正确:HAVING可引用别名 SELECT department, COUNT(*) AS dept_count FROM employees GROUP BY department HAVING dept_count > 10; -- ✅ ``` #### 二、实际应用示例 **场景**:统计平均工资超过6000的部门 ```sql SELECT department, AVG(salary) AS avg_salary FROM employees -- 先过滤掉无效数据(如离职员工) WHERE status = 'active' -- 按部门分组 GROUP BY department -- 再过滤分组结果 HAVING avg_salary > 6000; ``` - `WHERE status='active'` 先过滤掉非活跃员工,减少分组计算量 - `HAVING avg_salary>6000` 对分组后的聚合结果进行筛选 #### 三、性能优化建议 1. **优先使用WHERE** 在分组前用`WHERE`过滤掉无关数据,可显著提升性能。例如: ```sql -- 优化前(低效) SELECT department, COUNT(*) FROM employees GROUP BY department HAVING salary > 5000; -- 分组后过滤 -- 优化后(高效) SELECT department, COUNT(*) FROM employees WHERE salary > 5000 -- 先过滤再分组 GROUP BY department; ``` 2. **避免HAVING替代WHERE** 以下写法虽然结果相同,但效率低下: ```sql -- ❌ 错误用法(HAVING处理原始数据) SELECT * FROM orders HAVING order_date > '2023-01-01'; -- ✅ 正确用法 SELECT * FROM orders WHERE order_date > '2023-01-01'; ``` > **关键结论**: > - 对**原始数据行**过滤 → 用`WHERE` > - 对**分组聚合结果**过滤 → 用`HAVING` > - 两者可组合使用:`WHERE`前置过滤减少计算量,`HAVING`后置筛选分组结果[^3][^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值