HAVING 子句如何真正起作用?
Posted
技术标签:
【中文标题】HAVING 子句如何真正起作用?【英文标题】:How does the HAVING clause really work? 【发布时间】:2015-10-30 07:40:20 【问题描述】:我们可以在 SQL 查询中使用 HAVING 子句来过滤行组。当我们使用 GROUP BY 子句时,它直接以这种方式工作。
但是,让我们看看这个查询:
select 1 where 1!=1 having count(*)=0;
(或为 Oracle 附加 'from dual')。
如果 HAVING 真的做组过滤,在 WHERE 之后我们没有任何行,所以我们没有任何组,结果必须是 'No row selected'。
但在 PostgreSQL、mysql 和 Oracle 中,我们得到“1”作为查询结果。
问题:HAVING 究竟是如何工作的?
用于测试的 SQL Fiddle:http://www.sqlfiddle.com/#!15/d5407/51
【问题讨论】:
检测表是否有 0 行的愚蠢方法... WHERE 返回 0 行,所以我们有 0 组行。如果 HAVING 只做行组过滤,为什么要开始并为空输入做一些评估? 【参考方案1】:如果没有GROUP BY
,聚合总是返回一行,在您的情况下,COUNT(*)
返回0
。
此列不在您的选择列表中,而是硬编码文字1
select count(*) where 1!=1 ;
select 'bla' where 1!=1 having count(*)=0;
见fiddle
【讨论】:
好的,如果没有 GROUP BY 的 HAVING 总是返回一行,这行包含什么数据? @potapuff:如果没有匹配的行,COUNT
返回零,SUM
、MIN
等为 NULL。【参考方案2】:
HAVING
没有GROUP BY
cluase 是有效的并且对整个表进行操作。来自 SQL 标准 92:
7.10
::= 拥有
语法规则
1) 设 HC 为 .设 TE 是立即包含 HC 的那个。
如果 TE 不立即包含 a ,则 GROUP BY ( ) 是隐含的。
和:
::= 分组方式
<grouping specification> ::= <grouping column reference> | <rollup list> | <cube list> | <grouping sets list> | <grand total> | <concatenated grouping> <grouping set> ::= <ordinary grouping set> | <rollup list> | <cube list> | <grand total> <grand total> ::= <left paren> <right paren>
如您所见,GROUP BY ()
被视为 grand total
。
在您的示例中,您有:
select 1
where 1!=1
having count(*)=0;
实际上是这样的:
select 1
where 1!=1
-- group by ()
having count(*)=0;
【讨论】:
顺便说一句,大多数数据库(MySQL、PostgreSQL、Oracle)不支持 GROUP BY () :)以上是关于HAVING 子句如何真正起作用?的主要内容,如果未能解决你的问题,请参考以下文章