ANSI SQL标准为空结果集上的聚合函数定义(第6.5节,集合函数规范)以下行为:

COUNT(...) = 0
AVG(...) = NULL
MIN(...) = NULL
MAX(...) = NULL
SUM(...) = NULL


为AVG,MIN和MAX返回NULL使得完美的意义是,因为未定义空集的平均值,最小值和最大值。

最后一个困扰我:从数学上来说,空集的SUM是定义明确的:0。使用0(加法的中性元素)作为基本情况使所有内容保持一致:

SUM({})        = 0    = 0
SUM({5})       = 5    = 0 + 5
SUM({5, 3})    = 8    = 0 + 5 + 3
SUM({5, NULL}) = NULL = 0 + 5 + NULL


SUM({})定义为null基本上使“无行”成为一种特殊情况,不会适合其他人:

SUM({})     = NULL  = NULL
SUM({5})    = 5    != NULL + 5 (= NULL)
SUM({5, 3}) = 8    != NULL + 5 + 3 (= NULL)


我错过的选择(SUM为NULL)有明显的优势吗?

评论

注意:这是我在StackOverflow上专门针对SQL Server提出的问题的概括版本。

是的,我同意:COUNT和SUM的行为不一致。

#1 楼

恐怕原因仅在于,在SQL聚合及其与数学的联系不如现在理解的时候,这些规则是以一种即席方式设置的(就像ISO SQL标准的许多其他“功能”一样) (*)。

这只是SQL语言中极为众多的不一致之一。它们使语言变得更难教,更难学,更难理解,更难使用,更难于您想要的任何东西,但这就是事实。出于向后兼容的明显原因,不能将规则“冷”和“那样”更改(如果ISO委员会发布了该标准的最终版本,而供应商随后着手实施该标准,那么那些供应商将不会欣赏如果在后续版本中更改了规则,则该标准将非常大,以至于该标准的旧版本的现有(兼容)实现“自动不符合”新版本...)

(* )现在更好地理解,如果空集上的聚合系统地返回手头基础二进制运算符的标识值(即您所谓的“中性元素”),则其行为会更加一致。 COUNT和SUM的基础二进制运算符是加法,其标识值为零。对于MIN和MAX,如果有关类型是有限的,则该标识值分别是当前类型的最高值和最低值。但是,在这方面,平均,谐波均值,中位数等情况极为复杂且异乎寻常。

评论


我认为null对具有min和max的空集有意义。您可能会说一个身份值确实是未知的,但由于n * 0始终为0的相同原因,无值之和为0。但是min和max不同。我认为没有在任何记录上正确定义结果。

–克里斯·特拉弗斯(Chris Travers)
2012年10月5日12:14

同样,在空集上的avg()也可以视为空值,因为在此上下文中未正确定义0/0。

–克里斯·特拉弗斯(Chris Travers)
2012年10月5日12:16

MIN和MAX差别不大。分别采用基础二进制运算符LOWESTOF(x,y)和HIGHESTOF(x,y)。这些二进制运算符确实具有标识值。因为在两种情况下(如果所涉及的类型是有限的),实际上都存在一些值z,使得forall x:LOWESTOF(z,x)= x和forall y:HIGHESTOF(y,z)= y。 (两种情况下的身份值并不相同,但两种情况下都存在。)我同意,乍看之下,结果看起来非常违反直觉,但不可否认数学上的现实。

– Erwin Smout
2012年10月5日12:53



@Erwin:我同意您的所有观点,只是某些操作的标识(例如HIGHEST()可能不是数据类型的元素),例如Reals,其中标识为-Infinity(而LOWEST()为+ Infinity) )

–超立方体ᵀᴹ
2012年10月5日13:17



@SQL猕猴桃。您是否忘记了静态类型检查?如果像SUM()这样的表达式是由静态类型检查器处理的,就像它们总是返回整数一样,那么显然SUM()调用有时不可能返回非整数的内容(例如,空关系)。

– Erwin Smout
2012年10月5日在22:14

#2 楼

在务实的意义上,NULL的现有结果很有用。请考虑下表和语句:

C1 C2
-- --
 1  3 
 2 -1 
 3 -2 

SELECT SUM(C2) FROM T1 WHERE C1 > 9;

SELECT SUM(C2) FROM T1 WHERE C1 < 9;


第一条语句返回NULL,第二条语句返回零。如果一个空集对SUM返回零,则可能需要使用计数的另一种方法来从一个空集中区分出零的真实总和。如果我们确实希望空集为零,那么简单的COALESCE将满足该要求。

SELECT COALESCE(SUM(C2),0) FROM T1 WHERE C1 > 9;


评论


结果是,SUM(set1和set2的联合)<> SUM(set1)+ SUM(set2),因为任何数字+ NULL = NULL。这对您有意义吗?

–A-K
2012年10月5日14:15



@Leigh:像这样使用COALESCE()不会将空集的(0)和与(NULL)和区分开(例如表中有(10,NULL)行。

–超立方体ᵀᴹ
2012年10月5日14:26

此外,我们仍然无法区分SUM(空集)和SUM(一个或多个NULL集)。我们是否需要区分?

–A-K
2012年10月5日15:14

@AlexKuznetsov-只要至少一行包含一个值,我们就可以从一个包含一个或多个null的集合的总和中区分出一个空集合的总和。您是正确的,如果该集合仅包含NULL,则我们无法将NULL集合与所有NULL值的集合区分开。我的意思并不是说它在每种情况下都是有用的,仅仅是它可以是有用的。如果我求和一列并返回零,则无需检查是否至少有一个非NULL行用于显示结果,我就知道了。

–雷·里菲尔(Leigh Riffel)
2012年10月5日15:30

@ypercude-您完全正确。我的观点是,SUM的当前行为确实将空集与包含值的集区分开(即使某些值为空)。当不需要区分时,使用COALESCE比在区分时使用像DECODE(count(c2),0,NULL,sum(c2))这样的方法更简单。

–雷·里菲尔(Leigh Riffel)
2012年10月5日17:07

#3 楼

我可以看到的主要区别在于数据类型。 COUNT具有明确定义的returntype:整数。所有其他依赖于他们正在查看的列/表达式的类型。它们的返回类型必须与集合的所有成员兼容(请考虑浮点数,货币,十进制,bcd,时间跨度,...)。由于没有设置,因此您不能隐含返回类型,因此NULL是最佳选择。

注意:在大多数情况下,您可以隐含所查看列类型的返回类型,但可以不仅要对列求和,还要对所有事物求和。在某些情况下,即使不是不可能,暗示返回类型可能会变得非常困难,尤其是当您考虑标准的可能扩展时(想到动态类型)。

评论


为什么我们不能在SUM(column)表达式中暗示返回类型?我们没有空表吗?所有的列都有定义的类型吗?为什么对空结果集应该有什么不同?

–超立方体ᵀᴹ
2012年10月5日在12:04



您在说“因为没有设置”的地方弄错了。有一套。涉及的列或表达式的声明类型的所有可能值的集合。即使您正在查看的表为空,该声明的类型也存在。即使是空表也有标题。并且该声明的类型正是您的“隐式返回类型”。

– Erwin Smout
2012年10月5日13:09

你们俩都看过我的笔记吗?是的,到目前为止,它适用于基于列的SUM。但是,一旦遇到可变数据类型列(不在SQL Server中),您就很不走运。

– TToni
2012年10月5日14:12

在这种情况下,您将如何定义总和? 24 + 56.07 +'2012-10-05'+'红色'的结果将是什么?我的意思是,当定义加法时遇到问题时,不必担心SUM()的行为。

–超立方体ᵀᴹ
2012年10月5日14:28



@TToni:“尤其是当您考虑标准的可能扩展时”并不是OP所指的上下文。 OP非常清楚地指的是该标准的当前版本,该版本不包含任何“动态类型”或类似概念。 (哦,我只是发表评论,但没有拒绝投票。除了我所提出的那点小疏漏之外,您的回答中没有什么错误足以使我感到失望。)IMO。

– Erwin Smout
2012年10月5日在22:08