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 返回零,SUMMIN 等为 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 子句如何真正起作用?的主要内容,如果未能解决你的问题,请参考以下文章

isAuthenticated() 如何真正起作用?

绑定到集合是如何真正起作用的?

端口号如何在 TCP 中真正起作用?

姜戈。 Q() 如何真正起作用?

Sklearn 潜在狄利克雷分配如何真正起作用?

SQL Server ReadCommitted 隔离级别如何真正起作用?