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
语句中的HAVING
和WHERE
有什么区别?
编辑:我已将 Steven 的答案标记为正确答案,因为它包含链接上的关键信息:
当不使用
GROUP BY
时,HAVING
的行为类似于WHERE
子句
我看到WHERE
没有GROUP BY
的情况是我开始困惑的地方。当然,在您知道这一点之前,您不能在问题中指定它。
【问题讨论】:
你引用的那行根本不是关键。关键位 as wcm pointed out 是HAVING
是一个聚合后过滤器,而 WHERE
是一个预聚合过滤器。
这个链接比下面的所有 cmets 更能帮助我理解它,认为有人可以通过这个codeproject.com/Articles/25258/…得到帮助
另外,请考虑使用不带GROUP BY
的HAVING
代替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->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】:WHERE
和 HAVING
子句的区别:
WHERE
和HAVING
子句的主要区别在于,WHERE
用于行操作,HAVING
用于列操作。
为什么我们需要HAVING
子句?
众所周知,聚合函数只能在列上执行,所以我们不能在WHERE
子句中使用聚合函数。因此,我们在HAVING
子句中使用聚合函数。
【讨论】:
【参考方案10】:一种理解方式是,have 子句是 where 子句的附加过滤器。
WHERE 子句用于过滤结果中的记录。过滤器发生在进行任何分组之前。 HAVING 子句用于过滤组中的值
【讨论】:
【参考方案11】:在聚合查询中,(使用聚合函数的任何查询)where 子句中的谓词在生成聚合中间结果集之前进行评估,
Having 子句中的谓词在生成聚合结果集后应用于聚合结果集。这就是为什么聚合值的谓词条件必须放在Having 子句而不是Where 子句中的原因,以及为什么您可以在Having 子句中使用Select 子句中定义的别名,而不是在Where 子句中。
【讨论】:
【参考方案12】:我遇到了一个问题,发现WHERE
和HAVING
之间的另一个区别。它对索引列的作用不同。
WHERE my_indexed_row = 123
将显示行并自动对其他索引行执行“ORDER ASC”。
HAVING my_indexed_row = 123
显示从最旧的“插入”行到最新行的所有内容,没有排序。
【讨论】:
您怎么知道这是两者之间的定义差异,而不是您使用的特定 SQL 服务器的意外实现? 我刚刚在 MariaDB 上进行了测试。我猜是我 8 年前使用的 SQL 服务器产生了不同的结果。【参考方案13】:当不使用GROUP BY
时,WHERE
和HAVING
子句本质上是等价的。
但是,当使用GROUP BY
时:
WHERE
子句用于过滤结果中的记录。这
在进行任何分组之前进行过滤。
HAVING
子句用于过滤组中的值(即,
聚合成组后检查条件)。
来自Here的资源
【讨论】:
拥有和在哪里本质上是不等价的。执行时会报错。在 HAVING 子句中无效,因为它既不包含在聚合函数中,也不包含在 GROUP BY 子句中。【参考方案14】:来自here。
SQL 标准要求 HAVING 必须只引用 GROUP BY 子句或列中使用 聚合函数
与应用于数据库行的 WHERE 子句相反
【讨论】:
消息来源说,“不推荐使用列位置,因为语法已从 SQL 标准中删除。”遗憾的是,这是错误的:标准中从未删除任何内容,具有讽刺意味的是,这就是为什么在派生表“弃用”几十年后我们仍然拥有HAVING
的原因。
有点迂腐,但引用不正确,例如考虑SELECT 1 FROM T HAVING COUNT(*) >= 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
现在,我们要获取userid
s 和sum(dailyincome)
的sum(dailyincome)>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有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章