为啥将 count(*) 添加到 select 语句会强制行存在于子查询中?

Posted

技术标签:

【中文标题】为啥将 count(*) 添加到 select 语句会强制行存在于子查询中?【英文标题】:Why does adding count(*) to a select statement force a row to exist in a subquery?为什么将 count(*) 添加到 select 语句会强制行存在于子查询中? 【发布时间】:2009-06-10 18:53:03 【问题描述】:

在 Oracle 9i 上,为什么下面会产生结果 'abc'

select 'abc ' || (select txt from 
     (select 'xyz' as txt from dual where 1=2)) 
from dual

虽然这会产生“abc xyz”:

select 'abc ' || (select txt from 
     (select count(*), 'xyz' as txt from dual where 1=2)) 
from dual

为什么在子查询中添加 count(*) 会导致不同的行为?谓词 where 1=2 是否应该排除子查询中的任何结果?

【问题讨论】:

【参考方案1】:
select count(*) from dual where 1=2

返回 0。即值为 0 的行。

【讨论】:

绝对正确......这个问题出现在一个更复杂的查询中,它被其他行为所掩盖。我终于意识到了错误——原来的开发者确实需要使用 count(*) over()——解析函数正确返回 NULL——这正是开发者在这种情况下真正想要的。【参考方案2】:

它返回子查询中所有内容的计数,正确为 0。使用聚合函数始终(并且正确)以这种方式运行,并且是 SQL 标准的一部分。

【讨论】:

【参考方案3】:

count 将始终返回一个数值,0 或正整数,因此您的结果集中始终只有一行。

请注意,其他聚合函数可能会返回 NULL

【讨论】:

【参考方案4】:

了解聚合函数如何在 SQL 中运行对于编写正确的查询至关重要。向查询添加聚合函数(如 sum、avg、min、max、count)时,您要求数据库对一组结果执行组操作。大多数聚合,如 min 和 max,在有一组空行进行操作时将返回 null。例外情况是 count() - 它(正确地) 在出现空集或行时返回 0。

这个问题源于对一个更复杂的查询的分析——一个在 select 子句中有多个子查询表达式的查询。事实证明,在 select 表达式中添加 count(*) 对结果造成了一些破坏 - 因为它开始返回一个预期没有的值。

开发人员真正想要的是 count(*) 会产生 null 的情况。实现这一目标的最简单方法是使用 Oracle 中的分析。可以编写查询以使用等效的分析计数:count(*) over ()

select 'abc ' || (select txt from 
     (select count(*) over (), 'xyz' as txt from dual where 1=2)) 
from dual

【讨论】:

【参考方案5】:
 (select 'xyz' as txt from dual where 1=2)) 

此子查询不返回任何行。

 (select count(*), 'xyz' as txt from dual where 1=2)) 

此子查询始终返回 1 行。

这就是行为不同的原因。

【讨论】:

以上是关于为啥将 count(*) 添加到 select 语句会强制行存在于子查询中?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 COUNT(*) 需要对 SQL Server 上的所有表列具有 SELECT 权限?

为啥 .Select 或 .ToList() 提供嵌套 JSON,而 .Count 在父 JSON 中出现?

为啥 SQL SELECT 语句在 Java Spring boot 项目中不返回 COUNT() 结果?

sql动态拼接:为啥select count(*) where条件后面<if test="">不起作用?

为啥select count(_) from t,在InnoDB引擎中比MyISAM 慢

为啥在使用“.count”返回 Swift 下标计数时收到不正确的数组计数?