【问题标题】:Change aggregate functions to output NULL when a element is NULL当元素为 NULL 时,将聚合函数更改为输出 NULL
【发布时间】:2014-03-03 21:46:56
【问题描述】:

我搜索的关于警告的每个问题

警告:空值被聚合或其他 SET 操作消除。

通常人们希望将 NULL 值视为 0。我想要相反,如何修改以下存储过程以使其返回 NULL 而不是 1?

CREATE PROCEDURE TestProcedure 
AS
BEGIN
select cast(null as int) as foo into #tmp

insert into #tmp values (1)

select sum(foo) from #tmp
END
GO

我以为是SET ANSI_NULLS ON(我在声明之前、在过程本身以及在我的测试查询中执行过程之前尝试过)但这似乎并没有改变SUM( 的行为。

【问题讨论】:

  • 所以如果集合中的任何元素为 null,您希望聚合函数返回 null?

标签: sql sql-server stored-procedures null sql-server-2012


【解决方案1】:

sum() 函数会自动忽略 NULL。为了做你想做的事,你需要一个明确的检查:

select (case when count(foo) = count(*) then sum(foo) end)
from #tmp;

如果要明确,可以将else NULL 添加到case 语句中。

这背后的逻辑是count(foo) 计算foo 中非NULL 值的数量。如果这等于所有行,则所有值都是非 NULL。你可以使用更详细的:

select (case when sum(case when foo is null then 1 else 0 end) > 0
             then sum(foo)
        end)

而且,我想指出,这个标题非常具有误导性。 1 + NULL = NULL。问题在于聚合函数,而不是算术运算符。

【讨论】:

  • 会不会因为计算两次而对大表造成很大的性能损失?
  • EXISTS 会更快吗?
  • @ScottChamberlain 。 . .您可能不会注意到性能上的差异。查询的大部分时间将用于遍历数据页并从磁盘中获取它们。与这项工作相比,count() 的开销应该很小。
  • @DStanley 。 . .我对此表示怀疑。无论如何,查询都必须进行聚合,因此添加连接(exists 隐式执行)似乎不会加快速度。当然,OP可以尝试,我可能错了,但这是我的直觉。
  • 视情况而定。如果foo 被索引,它可以确定NULL 快速存在,从而避免整个扫描。
【解决方案2】:

EXISTS 寻找空值可能是最快的:

SELECT
    CASE WHEN EXISTS(SELECT NULL FROM tmp WHERE foo IS NULL)
        THEN NULL
        ELSE (SELECT sum(foo) from tmp)
    END

【讨论】:

    【解决方案3】:

    随便说说

    select case sign(sum(case when foo is null then 1 else 0 end))
           when 1 then null
           else        sum(foo)
           end
     from some_table
     ...
     group by
     ...
    

    这就是你所需要的。

    【讨论】:

      猜你喜欢
      • 2022-01-22
      • 2015-08-26
      • 2015-01-26
      • 2019-08-23
      • 2023-03-08
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多