15

当遇到空值时,将不胜感激解释 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列的类型是number

4

7 回答 7

13

如果您正在寻找这种行为的基本原理,那么可以在 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 的聚合函数将始终返回单行,即使没有可供选择的数据也是如此。

所以 ...

Coalesce(Count(<expression>),0)

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

于 2013-07-07T15:47:42.410 回答
12

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

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

这仅在一种情况下有所不同 - 当汇总的序列不包含数字项时,只有NULLs:如果至少存在一个数字,则结果将是数字。

于 2013-07-07T11:09:15.230 回答
4

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

文档中引用:

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

NULL 没有数据类型,因此您的第一个示例必须返回 null;因为 NULL 不是数字。

您的第二个示例对列中的数值求和。0 + null + 1 + 2 之和为 3;NULL 仅表示此处不存在数字。

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

于 2013-07-07T11:10:17.510 回答
4

算术聚合函数忽略空值。

  • SUM()忽略他们
  • AVG()计算平均值,就好像空行不存在(空值不计入总数或除数)
于 2013-07-07T11:11:25.280 回答
2

正如 Bohemian 所指出的,SUM 和 AVG 都排除了其中包含 NULL 的条目。这些条目不会进入聚合。如果 AVG 将 NULL 条目视为零,它将使结果偏向零。

在不经意的观察者看来,好像 SUM 将 NULL 条目视为零。真的把他们排除在外了。如果排除所有条目,则结果根本没有值,即 NULL。您的示例说明了这一点。

于 2013-07-07T11:58:51.253 回答
1

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

结果为空!如果任何操作数为空,类似的语句会给出结果为空。

于 2017-10-27T16:15:52.570 回答
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);
于 2021-07-08T16:56:14.017 回答