为什么在聚合函数和标量函数中对 NULL 的处理方式不同?

Why is NULL handled differently in aggregate and scalar functions?

提问人:David542 提问时间:6/10/2023 最后编辑:Thomas DickeyDavid542 更新时间:6/22/2023 访问量:195

问:

让我们来看看以下两个问题:

select greatest(1, val) from unnest([null]) as val
# null

和:

select sum(val) from unnest([1, null]) as val
# 1

我的问题是为什么聚合函数和普通标量函数之间的处理方式不同?当然,当不计算值时,第二个查询更有用。但我认为如果它要返回而不是 .如果是一个“未知值”,那么两个函数不是都有一个假定的未知答案(即,),而不仅仅是后者吗?nullnull1nullnullnull

如果这有历史原因,那也很高兴知道。希望有人能阐明为什么两者之间存在差异。

ANSI-SQL 数据库无关

评论

1赞 Martin Smith 6/10/2023
基本上是因为我认为这是SQL标准在当时决定的。当 ANSI 警告处于打开状态时,SQL Server 将打印一条消息,告知您在聚合中忽略 NULL。我假设他们认为这在实践中会更有用,即使逻辑上有些不一致。

答:

1赞 Parfait 6/10/2023 #1

如果没有具体的引用,原因可能是由于比较函数(如)与计算函数(如 )。GREATESTSUM

在 ANSI SQL 中,将任何值(使用 、、、 等运算符)进行比较时,应始终返回 unknown 或 。有趣的是,默认情况下,不同的 RDBMS 可能不会完全遵循此规则,因此可以重新调整非零行。请参阅 SQL Server 的 SET ANSI_NULLS模式下的讨论。另请参阅 Postgres 的transform_null_equals模式。<>=<>NULLNULLWHERE my_column <> NULL

另一方面,在 ANSI SQL 中也是如此,就像大多数聚合函数一样,除了忽略 s。因此,您观察到不同的行为。SUMCOUNT(*)NULL

4赞 Salman A 6/13/2023 #2

聚合函数应该跳过 null 值。以下是 SQL-92 标准的摘录:

<设置功能规范>

[...]

否则,让 TX 成为 将<值表达式>应用于 T 的每一行并消除 null 值。如果消除一个或多个 null 值,则 引发完成条件:警告 - 集合中消除的 null 值 功能。

另一方面,如果任何参数为 null¹,则该函数应返回 null。greatest

我的问题是为什么在聚合之间以不同的方式处理 null 函数和普通标量函数?

一般来说,如果标量函数的任何参数为 null²,则返回 null。以下是 Ask Tom 对这个完全相同的问题的看法,我个人同意答案中所说的一切:

汤姆说......

几乎所有的单行函数都返回 NULL,如果其中任何一个 要比较的输入为 null。

ops$tkyte%ORA10GR2> select round( 1.2, null ) from dual;

ROUND(1.2,NULL)
---------------
NULL

当你问“1、NULL、2 中最大的是什么——答案是”我们 不知道,因为 NULL 是未知的”

聚合被定义为“跳过空值”(ANSI 是这样说的)

但通常采用一组输入的函数将返回 NULL 当决定性输入为 NULL 时。

http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions001.htm#i88893

如果调用带有 null 参数的 SQL 函数,则 SQL 函数 自动返回 null

¹ 在最大功能标准化之前很久就已经存在了不同的实现。如果任何参数为 null,MySQLOracle 返回 null;而 PostgreSQLSQL Server 忽略 null 值。

² 相反,存在跳过 null 值的供应商特定标量函数。一个例子是 (MySQL, PostgreSQL, SQL Server) 函数,该函数旨在使用分隔符简化(可能为 null)字符串的连接。concat_ws

评论

0赞 jarlh 6/22/2023
GREATEST 被纳入 SQL 标准已经有好几个星期了!SQL-2023 拥有它,而且至少也是如此。en.wikipedia.org/wiki/SQL:2023
0赞 Salman A 6/22/2023
太好了,不幸的是,规格不是免费提供的(AFAIK),所以不能说以上两种行为中的哪一种是标准的,
0赞 jarlh 6/22/2023
如果其任何值为 null,则返回 null。
1赞 Salman A 6/22/2023
对 SQL Server 和 PostgreSQL 感到难过。我会在几个小时内修改答案。感谢您的指正。