SQL中HAVING和WHERE的区别是什么?

285

HAVINGWHERESQL SELECT语句中有什么区别?

编辑:我已将Steven的答案标记为正确答案,因为它包含了该链接上的关键信息:

当未使用GROUP BY时,HAVING的行为类似于WHERE子句。

我曾经看到WHERE的情况没有使用GROUP BY,这就是我的困惑所在。当然,除非你知道这一点,否则你无法在问题中指定它。


48
你引用的那行话并不是关键部分。关键在于,正如wcm指出的HAVING是一个聚合后的过滤器,而WHERE是一个聚合前的过滤器。 - Nick Chammas
1
这个链接帮助我更好地理解了它,比下面所有的评论都要好,我认为有人可能会从中得到帮助。 http://www.codeproject.com/Articles/25258/Where-Vs-Having-Difference-between-having-and-Wher - Lijin Durairaj
另外,请注意,在某些数据库中,如Oracle,使用HAVING而不带GROUP BY作为WHERE的替代方法并不被普遍接受。 - Saeed Ahadian
18个回答

405

HAVING:用于在聚合完成后检查条件。
WHERE:用于在聚合之前检查条件。

这段代码:

select City, CNT=Count(1)
From Address
Where State = 'MA'
Group By City

提供了一个包含马萨诸塞州所有城市及每个城市地址数量的表格。

此代码:

select City, CNT=Count(1)
From Address
Where State = 'MA'
Group By City
Having Count(1)>5

提供了一个包含马萨诸塞州拥有五个以上地址的城市及每个城市地址数量的表格。


11
这应该是被接受的答案。将“having”和“where”的区别分清楚,使其立即清晰明了。 - Paul

100

HAVING用于SELECT语句中对分组或聚合函数指定搜索条件。

来源


29
我的第一点区别是:如果从SQL语言中删除HAVING,那么生活还会继续,或多或少地保持原样。当然,少数查询需要使用派生表、CTE等来重写,但由于这个原因,它们可能更容易理解和维护。也许供应商的优化器代码需要重新编写以解决这个问题,这是行业改进的机会。
现在考虑一下从语言中删除WHERE。这时,大多数现有的查询都需要重写,而没有明显的替代构造。程序员必须变得有创意,例如,使用内部连接到一个已知包含恰好一行的表(例如Oracle中的DUAL),使用ON子句模拟先前的WHERE子句。这种构造是牵强附会的;很明显语言中缺少了某些东西,情况会更糟。
简而言之,我们明天可能失去HAVING,事情不会更糟,可能会更好,但不能这样说WHERE
从这里的答案中可以看出,许多人并不知道HAVING子句可以在没有GROUP BY子句的情况下使用。在这种情况下,HAVING子句应用于整个表达式,并要求SELECT子句中只出现常量。通常,HAVING子句涉及聚合。
这比听起来更有用。例如,考虑以下查询,以测试T中所有值的name列是否唯一:
SELECT 1 AS result
  FROM T
HAVING COUNT( DISTINCT name ) = COUNT( name );

只有两种可能的结果:如果HAVING子句为真,则结果将是包含值1的单行,否则结果将为空集。


这是否等同于 "SELECT COUNT( DISTINCT name ) = COUNT( name ) FROM T"? - MSpreij
@MSpreij 不知道这对你是否有用,但它在 SQL Server 2005 上不起作用,但第一个可以。 - Joe

22

由于GROUP BY和HAVING都是可选的,因此图表显示了两种情况,请按照箭头操作。 - Paul Sweatte
我不知道你在第二个链接中提到的行为是什么。期望的结果是你修复图表以显示我提到的有效(显式)路径。想一想:图表涵盖了整个查询,但问题只关心“WHERE->HAVING”部分,所以我认为它值得仔细注意。如果你认为我的答案是错误的,那么就编辑它或在评论中发表建议的修正意见。 - onedaywhen
@onedaywhen 第二个链接提到了“将HAVING条件应用于行而不是组”。这是非标准还是标准?是否总是、从不或有时存在隐含的GROUP BY?这种行为是否100%符合标准,已弃用,反模式,实现相关或具有未来性? - Paul Sweatte
“HAVING条件应用于行而不是组”对我来说听起来像是错误的想法。在我看来,这种行为最好在同一个答案中说明:“HAVING子句从最终结果中排除不符合其搜索条件的行”,就这么简单,100%标准兼容。如果没有GROUP BY,那么就没有隐式分组。但我仍然有点困惑,不知道这与您的图表缺少有效路径有何关系。 - onedaywhen
快速验证:CREATE TABLE T (c CHAR(1)); INSERT INTO T VALUES ('a'),('a'); SELECT 'true' FROM T HAVING COUNT (c) = 2; 应该是单行单列结果,显示 true,因为搜索条件没有删除任何行,即未应用隐式分组(如果有分组,则 COUNT(c) 将为 1,搜索条件将失败,即零行结果)。 - onedaywhen
显示剩余4条评论

22

由于 WHERE 关键字不能与聚合函数一起使用,因此 HAVING 子句被添加到 SQL 中。

查看此w3schools链接以获取更多信息。

语法:

SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value

如下查询语句:

SELECT column_name, COUNT( column_name ) AS column_name_tally
  FROM table_name
 WHERE column_name < 3
 GROUP 
    BY column_name
HAVING COUNT( column_name ) >= 3;

可以使用派生表(并省略 HAVING)来重新编写如下:

SELECT column_name, column_name_tally
  FROM (
        SELECT column_name, COUNT(column_name) AS column_name_tally
          FROM table_name
         WHERE column_name < 3
         GROUP 
            BY column_name
       ) pointless_range_variable_required_here
 WHERE column_name_tally >= 3;

4
你稍微误解了意思:HAVING是因为语言中没有派生表格而被添加的,直到它们被加入后SQL才具备关系完备性,一旦它们被不可避免地加入,HAVING就变得多余了。 - onedaywhen

12

HAVING是在使用诸如GROUP BY的聚合时使用的。

SELECT edc_country, COUNT(*)
FROM Ed_Centers
GROUP BY edc_country
HAVING COUNT(*) > 1
ORDER BY edc_country;

8

WHERE子句不能用于聚合函数
意思是:您不应该像这样使用
附加信息:表名

SELECT name  
FROM bonus  
GROUP BY name  
WHERE sum(salary) > 200  

在使用HAVING子句的情况下,不需要使用WHERE子句。如果没有使用GROUP BY子句,则HAVING子句就像WHERE子句一样起作用。

SELECT name  
FROM bonus  
GROUP BY name  
HAVING sum(salary) > 200  

这是一个非常重要的观点,在被接受的答案和得票最高的答案中都被忽视了! - Yahya

8

WHERE在SQL中用于限制返回的数据集,它使用SQL内置的集合操作和索引,因此是过滤结果集最快的方法。尽可能使用WHERE。

HAVING对于一些聚合过滤是必需的。它在SQL检索、组装和排序结果后再进行过滤。因此,它比WHERE慢得多,除非必须使用HAVING,在其他情况下应该避免使用。

即使使用WHERE会更快,SQL Server也允许您使用HAVING。不要这样做。


SQL语言中对派生表的支持意味着你的断言“HAVING在某些聚合过滤器中是必需的”是错误的。 - onedaywhen
1
这是一个很好的观点。自从我写下这个答案以来的三年里,我肯定更倾向于使用派生表,而以前我会使用HAVING。我还没有仔细思考过HAVING是否仍然有一些有意义的用例。我也不知道派生表是否普遍比HAVING表现更好。 - davidcl

4

WHEREHAVING子句的区别:

WHERE用于行操作,而HAVING用于列操作。

为什么我们需要HAVING子句?

正如我们所知,聚合函数只能在列上执行,因此我们无法在WHERE子句中使用聚合函数。因此,我们使用HAVING子句来使用聚合函数。


2

可以这样理解:having子句是where子句的一个额外条件过滤器。

WHERE子句用于在结果集中筛选记录。过滤发生在任何分组之前。而HAVING子句用于从分组中筛选值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接