为什么在Oracle中SUM(null)不为0?

时间:2013-07-07 11:02:46

标签: sql database oracle plsql

当遇到空值时,可以理解解释Oracle中SUM函数的内部功能:

的结果
select sum(null) from dual;
is null

但是当一个空值出现在值序列中时(如无效列的总和),空值的计算值将为0

select sum(value) from
(
select case when mod(level , 2) = 0 then null else level end as value from dual
connect by level <= 10
)
is 25

当看到

的结果时,这会更有趣
select (1 + null) from dual
is null

任何带null的操作都将导致null(is null运算符除外)。

==========================
由于评论而导致的某些更新:

create table odd_table as select sum(null) as some_name from dual;

结果:

create table ODD_TABLE
(
  some_name NUMBER
)

为什么some_name列的类型为数字

7 个答案:

答案 0 :(得分:10)

在计算NULL时,SQL不会将SUM值视为零,它会忽略它们:

  

返回表达式中所有值的总和,或仅返回DISTINCT值的总和。空值被忽略。

这仅在一种情况下产生差异 - 当总计的序列不包含数字项时,仅NULL s:如果至少存在一个数字,则结果将为数字。

答案 1 :(得分:10)

如果您正在寻找此行为的基本原理,那么可以在ANSI SQL标准中找到它,该标准规定聚合运算符忽略NULL值。

如果您想覆盖该行为,那么您可以自由地使用:

Sum(Coalesce(<expression>,0))

......虽然使用Sum()来更有意义......

Coalesce(Sum(<expression>),0)

你可能更有意义:

Avg(Coalesce(<expression>,0))

......或......

Min(Coalesce(<expression,0))

其他ANSI聚合怪癖:

  1. Count()永远不会返回null(当然还是否定的)
  2. 仅选择没有Group By的聚合函数将始终返回单行,即使没有可供选择的数据。
  3. 所以......

    Coalesce(Count(<expression>),0)
    

    ......浪费了良好的合并。

答案 2 :(得分:4)

你正在以错误的方式看待这个问题。 SUM()对列进行操作,并忽略空值。

引用the documentation

  

此函数将任何数值数据类型或任何可以隐式转换为数字数据类型的非数字数据类型作为参数。该函数返回与参数的数值数据类型相同的数据类型。

NULL没有数据类型,所以你的第一个例子必须返回null;因为NULL不是数字。

您的第二个示例对列中的数值求和。 0 + null + 1 + 2的总和为3; NULL只是意味着这里不存在数字。

你的第三个例子不是对列的操作;删除SUM(),答案将与虚无相同+ 1仍然是虚无。您不能像使用字符串那样将NULL转换为空数字,因为不存在空数字。它存在或不存在。

答案 3 :(得分:4)

算术聚合函数忽略 nulls。

  • SUM()忽略了他们
  • AVG()计算平均值,好像空行不存在一样(空值不计入总数或除数)

答案 4 :(得分:2)

正如波希米亚人指出的那样,SUM和AVG都排除了带有NULL的条目。这些条目不会进入汇总。如果AVG​​将NULL条目视为零,则会将结果偏向零。

对于不经意的观察者来说,似乎SUM将NULL条目视为零。它真的排除了它们。如果排除了所有条目,则结果根本没有值,即NULL。您的示例说明了这一点。

答案 5 :(得分:1)

这是不正确的:0 + null + 1 + 2的总和是3; 从dual中选择0 + null + 1 + 2总计;

结果为空! 如果任何操作数为null,则类似语句将结果赋值为null。

答案 6 :(得分:0)

如果您想求和而不忽略空值,这里有一个解决方案。

此解决方案将记录分为两组:空值和非空值。 NVL2(a, 1, NULL) 通过将所有非空值更改为 1 来实现这一点,以便它们以相同的方式排序在一起。然后对这两个组进行排序以将空组放在首位(如果有),然后仅对两组中的第一个进行求和。如果没有空值,则不会有空组,因此第一个组将包含所有行。相反,如果至少有一个空值,那么第一组将只包含这些空值,并且这些空值的总和将为空值。

SELECT SUM(a) AS standards_compliant_sum,
       SUM(a) KEEP(DENSE_RANK FIRST ORDER BY NVL2(a, 1, NULL) DESC) AS sum_with_nulls
  FROM (SELECT 41   AS a FROM DUAL UNION ALL
        SELECT NULL AS a FROM DUAL UNION ALL
        SELECT 42   AS a FROM DUAL UNION ALL
        SELECT 43   AS a FROM DUAL);

您可以选择包含 NULLS FIRST 以使其更清楚地了解正在发生的事情。如果您为了移动空值而有意进行排序,我总是建议您这样做以保持代码清晰。

SELECT SUM(a) AS standards_compliant_sum,
       SUM(a) KEEP(DENSE_RANK FIRST ORDER BY NVL2(a, 1, NULL) DESC NULLS FIRST) AS sum_with_nulls
  FROM (SELECT 41   AS a FROM DUAL UNION ALL
        SELECT NULL AS a FROM DUAL UNION ALL
        SELECT 42   AS a FROM DUAL UNION ALL
        SELECT 43   AS a FROM DUAL);