SQL中的HAVING和WHERE有啥区别?

Posted

技术标签:

【中文标题】SQL中的HAVING和WHERE有啥区别?【英文标题】:What is the difference between HAVING and WHERE in SQL?SQL中的HAVING和WHERE有什么区别? 【发布时间】:2010-09-22 04:42:05 【问题描述】:

SQL SELECT 语句中的HAVINGWHERE 有什么区别?

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

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

我看到WHERE 没有GROUP BY 的情况是我开始困惑的地方。当然,在您知道这一点之前,您不能在问题中指定它。

【问题讨论】:

你引用的那行根本不是关键。关键位 as wcm pointed out 是 HAVING 是一个聚合后过滤器,而 WHERE 是一个预聚合过滤器。 这个链接比下面的所有 cmets 更能帮助我理解它,认为有人可以通过这个codeproject.com/Articles/25258/…得到帮助 另外,请考虑使用不带GROUP BYHAVING 代替WHERE 在Oracle 等所有数据库中并不普遍。 【参考方案1】:

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

为您提供 MA 中超过 5 个地址的城市表以及每个城市的地址数。

【讨论】:

这应该是公认的答案。 “拥有”和“在哪里”之间的区别使这一点立即变得清晰。【参考方案2】:

HAVING 指定一个搜索条件 SELECT 语句中使用的组或聚合函数。

Source

【讨论】:

【参考方案3】:

对我来说,第一个区别是:如果从 SQL 语言中删除 HAVING,那么生活将或多或少像以前一样继续。当然,少数查询需要使用派生表、CTE 等重写,但可以说它们更容易理解和维护。也许需要重写供应商的优化器代码来解决这个问题,这又是一个行业内改进的机会。

现在考虑一下从语言中删除WHERE。这一次,存在的大部分查询需要在没有明显替代构造的情况下重写。编码员必须要有创造力,例如使用ON 子句模拟之前的WHERE 子句,对已知仅包含一行的表进行内部连接(例如,Oracle 中的DUAL)。这种结构是人为的;很明显,语言中缺少某些东西,结果情况会更糟。

TL;DR 我们明天可能会失去HAVING,情况不会更糟,可能会更好,但WHERE 却不能这样说。


从这里的答案来看,似乎很多人没有意识到 HAVING 子句可以在没有 GROUP BY 子句的情况下使用。在这种情况下,HAVING 子句应用于整个表表达式,并且要求在SELECT 子句中只出现常量。通常HAVING 子句将涉及聚合。

这比听起来更有用。例如,考虑这个查询来测试name 列对于T 中的所有值是否是唯一的:

SELECT 1 AS result
  FROM T
HAVING COUNT( DISTINCT name ) = COUNT( name );

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

【讨论】:

这是否等同于“SELECT COUNT(DISTINCT name) = COUNT(name) FROM T”? @MSpreij 不知道这是否适合您,但它不适用于 SQL Server 2005,但第一个可以【参考方案4】:

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

查看此w3schools link 了解更多信息

语法:

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;

【讨论】:

您稍微漏了点:添加了HAVING 是因为派生表尚未添加到语言中,直到它们是 SQL 才关系完整,一旦它们不可避免地成为 HAVING多余的。【参考方案5】:

两者的区别在于与GROUP BY子句的关系:

WHERE 在 GROUP BY 之前; SQL 在对记录进行分组之前评估 WHERE 子句。

HAVING 在 GROUP BY 之后; SQL 在对记录进行分组后评估 HAVING。

参考文献

SQLite SELECT Statement Syntax/Railroad Diagram

Informix SELECT Statement Syntax/Railroad Diagram

【讨论】:

由于 GROUP BY 和 HAVING 都是可选的,所以图表显示了这两种情况,只需按照箭头。 我对这个问题的回答中的示例查询:SELECT 1 AS result FROM T HAVING... - 在您的图表中,如果不通过GROUP BY,我无法到达HAVING,但我完全有效且有用的查询没有@987654330 @。次要观点:您无法选择在 SELECT 子句中包含文字值。 @onedaywhen 既然you know 关于隐含的 GROUP BY,为什么不提呢?你知道this behavior 是不是你所期待的吗? 我认为你是在断章取义地引用我的话。问题是关于 mysql 与标准的明显偏差,除了我回答的最后一段之外,所有内容都描述了标准的行为,最后一段提到“隐含的 GROUP BY 子句在其他答案中提到”。您是说您的图表旨在描述(所有)隐式行为吗?只坚持你需要编写的代码来获得所需的行为不是更有用吗? ...我不知道您在第二个链接中暗示了什么行为。期望的结果是您修复图表以显示我提到的有效(显式)路径。想一想:该图涵盖了整个查询,但问题只对WHERE-&gt;HAVING 部分感兴趣,所以我认为值得密切关注细节。如果您认为我的回答有误,请对其进行编辑或在 cmets 中发布建议的更正。【参考方案6】:

HAVING 用于当您使用 GROUP BY 等聚合时。

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

【讨论】:

【参考方案7】:

WHERE 被应用为对 SQL 返回的集合的限制;它使用 SQL 的内置集合操作和索引,因此是过滤结果集的最快方法。尽可能使用 WHERE。

HAVING 对于某些聚合过滤器是必需的。它在 sql 检索、组装和排序结果之后过滤查询。因此,它比 WHERE 慢得多,应该避免使用,除非在需要它的情况下。

即使 WHERE 更快,SQL Server 也可以让您轻松使用 HAVING。不要这样做。

【讨论】:

支持 SQL 语言中的派生表意味着您的断言“某些聚合过滤器需要 HAVING”是错误的。 这是一个很好的观点。自从我写下这个答案以来的三年里,我当然已经转向使用派生表,而我以前会使用 HAVING。我还没有考虑过 HAVING 是否仍然有一些有意义的用例的问题。我也不知道派生表的性能是否普遍优于 HAVING。【参考方案8】:

WHERE 子句不适用于聚合函数 意思是:你不应该这样使用 奖励:表名

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

HERE 而不是使用 WHERE 子句,您必须使用 HAVING..

不使用 GROUP BY 子句,HAVING 子句只用作 WHERE 子句

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

【讨论】:

【参考方案9】:

WHEREHAVING 子句的区别:

WHEREHAVING 子句的主要区别在于,WHERE 用于行操作,HAVING 用于列操作。

为什么我们需要HAVING 子句?

众所周知,聚合函数只能在列上执行,所以我们不能在WHERE子句中使用聚合函数。因此,我们在HAVING 子句中使用聚合函数。

【讨论】:

【参考方案10】:

一种理解方式是,have 子句是 where 子句的附加过滤器。

WHERE 子句用于过滤结果中的记录。过滤器发生在进行任何分组之前。 HAVING 子句用于过滤组中的值

【讨论】:

【参考方案11】:

在聚合查询中,(使用聚合函数的任何查询)where 子句中的谓词在生成聚合中间结果集之前进行评估,

Having 子句中的谓词在生成聚合结果集后应用于聚合结果集。这就是为什么聚合值的谓词条件必须放在Having 子句而不是Where 子句中的原因,以及为什么您可以在Having 子句中使用Select 子句中定义的别名,而不是在Where 子句中。

【讨论】:

【参考方案12】:

我遇到了一个问题,发现WHEREHAVING 之间的另一个区别。它对索引列的作用不同。

WHERE my_indexed_row = 123 将显示行并自动对其他索引行执行“ORDER ASC”。

HAVING my_indexed_row = 123 显示从最旧的“插入”行到最新行的所有内容,没有排序。

【讨论】:

您怎么知道这是两者之间的定义差异,而不是您使用的特定 SQL 服务器的意外实现? 我刚刚在 MariaDB 上进行了测试。我猜是我 8 年前使用的 SQL 服务器产生了不同的结果。【参考方案13】:

当不使用GROUP BY 时,WHEREHAVING 子句本质上是等价的。

但是,当使用GROUP BY 时:

WHERE 子句用于过滤结果中的记录。这 在进行任何分组之前进行过滤。 HAVING 子句用于过滤组中的值(即, 聚合成组后检查条件)。

来自Here的资源

【讨论】:

拥有和在哪里本质上是不等价的。执行时会报错。在 HAVING 子句中无效,因为它既不包含在聚合函数中,也不包含在 GROUP BY 子句中。【参考方案14】:

来自here。

SQL 标准要求 HAVING 必须只引用 GROUP BY 子句或列中使用 聚合函数

与应用于数据库行的 WHERE 子句相反

【讨论】:

消息来源说,“不推荐使用列位置,因为语法已从 SQL 标准中删除。”遗憾的是,这是错误的:标准中从未删除任何内容,具有讽刺意味的是,这就是为什么在派生表“弃用”几十年后我们仍然拥有HAVING 的原因。 有点迂腐,但引用不正确,例如考虑SELECT 1 FROM T HAVING COUNT(*) &gt;= 1; - 不引用GROUP BY 子句中的列(没有),也不引用聚合函数中的列(查询根本不引用列)。【参考方案15】:

在做一个项目时,这也是我的问题。如上所述,HAVING 检查已经找到的查询结果的条件。但 WHERE 用于在查询运行时检查条件。

让我举一个例子来说明这一点。假设你有一个这样的数据库表。

usertable int userid, date datefield, int dailyincome

假设表中有以下行:

1, 2011-05-20, 100

1, 2011-05-21, 50

1, 2011-05-30, 10

2, 2011-05-30, 10

2, 2011-05-20, 20

现在,我们要获取userids 和sum(dailyincome)sum(dailyincome)&gt;100

如果我们写:

SELECT userid, sum(dailyincome) FROM usertable WHERE sum(dailyincome)>100 GROUP BY userid

这将是一个错误。正确的查询是:

SELECT userid, sum(dailyincome) FROM usertable GROUP BY userid HAVING 总和(每日收入)>100

【讨论】:

【参考方案16】:

WHERE 子句用于比较基表中的值,而 HAVING 子句可用于过滤查询结果集中聚合函数的结果 点击here!

【讨论】:

【参考方案17】:

当不使用 GROUP BY 时,WHERE 和 HAVING 子句本质上是等价的。

但是,当使用 GROUP BY 时:

WHERE 子句用于过滤结果中的记录。这 在进行任何分组之前进行过滤。 HAVING 子句是 用于过滤组中的值(即,检查后的条件 已执行聚合到组)。

【讨论】:

【参考方案18】:

我使用 HAVING 来限制基于聚合函数结果的查询。例如。选择 * 在 blahblahblah 组中的某物有 count(SOMETHING)>0

【讨论】:

以上是关于SQL中的HAVING和WHERE有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL Query 中的 HAVING 和 WHERE 有啥区别?

SQL中WHERE 和HAVING的区别

GROUP BY,WHERE,HAVING之间的区别和用法

在oracle中where 子句和having子句中的区别

SQL中where与having的区别

having和where的区别