SQL中 where 和 having 子句具有不同的功能。但它们都会过滤掉一些行。
一般情况下 HAVING 子句通常与 group by 子句一起使用,对 group by 分组的结果再次进行筛选。having 子句将过滤条件应用于每组分行,而 where 子句是将过滤条件应用于每个单独的行。
下面让我们来详细了解一下。
在一个单表查询中,WHERE是在查询执行的开始阶段出现的。我们过去认为它决定了哪些行将被查询返回,但这并不准确。
WHERE决定了哪些行将被查询处理
。
当我们使用GROUP BY子句时,这种区别就很明显了。
HAVING是在查询执行的最后阶段出现的。
在所有的记录都被处理后,HAVING决定哪些记录将被发送到客户端
。
让我们看看WHERE和HAVING在使用中的区别。
当我们运行一个带GROUP BY的查询时,WHERE和HAVING的区别就很明显了。
SELECT department_id, count(*) AS employees_no
FROM employee
WHERE gender = 'F'
GROUP BY department_id
HAVING employees_no < 10;
该查询计算了每个部门的女员工人数,并且只返回女员工人数小于10的部门。
WHERE 筛选女性员工记录。对于非女性员工记录根本就不会被查询读取。
GROUP BY 对找到的记录进行分组(或聚合),对每个不同的 department_id 只产生一条记录。
HAVING 排除了 employees_no 小于10的聚合行。
请注意:
如果使用 WHERE employees_no < 10
会出错,因为这个值在聚合之前不存在。
如果使用 HAVING gender = 'F'
也会出错,因为性别列不存在于聚集的行中。
WHERE用于在任何分组发生之前过滤记录。
HAVING用于在分组后过滤值。只有组中的列或表达式才能包含在 HAVING子 句的条件中。
有时你可能认为 WHERE 和 HAVING 都可以使用,他们实现了同样的效果。比如:
SELECT *
FROM employee
WHERE date_of_birth > '2000-01-01';
这个查询是找到在本世纪出生的员工。
我们可以用 having 来代替 where 吗?从最终结果上看是可以的。但是 having 相当于我们告诉数据库要读取所有的记录,最终只返回符合条件的记录给客户端。这样查询相比较 where 会慢很多。
若使用 where 子句,相当于我们要求数据库只读取我们感兴趣的记录。如果有一个以 date_of_birth
列开始的索引,它将使用索引,这样会更快。
一些数据库管理系统(DBMS)足够聪明,可以将不必要的HAVING子句翻译成WHERE子句。但是并不是所有的DBMS都会这样做,可能总有一些复杂的情况下,DBMS无法应用这种优化。因此我们在设计sql语句时一定要注意区分使用。