【问题标题】:Getting warning: Null value is eliminated by an aggregate or other SET operation收到警告:空值被聚合或其他 SET 操作消除
【发布时间】:2013-09-10 12:50:50
【问题描述】:

我有这个架构

create table t(id int, d date) 

insert into t (id, d) values (1, getdate()), 
                             (2, NULL)

什么时候做

declare @mindate date    
select @mindate = min(d) from t

我收到警告

空值被聚合或其他 SET 操作消除

为什么以及我能做些什么?

【问题讨论】:

  • 尝试添加where d is not null
  • 我收到了同样的警告。我不介意警告本身,但是,我需要 SQL 代理运行存储过程,当我这样做时,警告会导致代理作业失败。
  • @Richie 它不会使 SQL 代理作业失败。它将出现在作业历史记录中可见的输出中,当作业因其他原因失败时,您可能正在查看它,因此假设是原因

标签: sql sql-server


【解决方案1】:

大多数情况下你不应该对此采取任何行动。

  • 可以通过将ansi_warnings 设置为关闭来禁用警告,但这有other effects, e.g. on how division by zero is handled,并且当您的查询使用索引视图、计算列或 XML 方法等功能时可能会导致失败。
  • 在某些有限的情况下,您可以重写聚合来避免它。例如COUNT(nullable_column) 可以重写为 SUM(CASE WHEN nullable_column IS NULL THEN 0 ELSE 1 END),但这并不总是可以在不改变语义的情况下直接完成。

这只是一条信息性消息required in the SQL standard。除了向消息流添加不需要的噪音之外,它没有任何不良影响(除了意味着 SQL Server 不能绕过读取 NULL 行,它可以有 an overhead 但禁用警告并不能提供更好的执行计划这方面)

返回此消息的原因是 SQL 中的大多数操作都会传播空值。

SELECT NULL + 3 + 7 返回NULL(将NULL 视为未知量,这是有道理的,因为? + 3 + 7 也是未知的)

但是

SELECT SUM(N)
FROM   (VALUES (NULL),
               (3),
               (7)) V(N) 

返回10 和空值被忽略的警告。

但是,对于典型的聚合查询,这些正是您想要的语义。否则,单个NULL 的存在将意味着该列上所有行的聚合总是最终产生NULL,这不是很有用。

下面哪个蛋糕最重?Image SourceCreative Commons 图片由我修改(裁剪和注释))

称完第三块蛋糕后,天平坏了,因此没有关于第四块蛋糕的信息,但仍然可以测量周长。

+--------+--------+---------------+
| CakeId | Weight | Circumference |
+--------+--------+---------------+
|      1 | 50     | 12.0          |
|      2 | 80     | 14.2          |
|      3 | 70     | 13.7          |
|      4 | NULL   | 13.4          |
+--------+--------+---------------+

查询

SELECT MAX(Weight)        AS MaxWeight,
       AVG(Circumference) AS AvgCircumference
FROM   Cakes 

返回

+-----------+------------------+
| MaxWeight | AvgCircumference |
+-----------+------------------+
|        80 |          13.325  |
+-----------+------------------+

尽管从技术上讲,不能肯定地说 80 是最重的蛋糕的重量(因为未知数可能更大),但上述结果通常比简单地返回未知数更有用。

+-----------+------------------+
| MaxWeight | AvgCircumference |
+-----------+------------------+
|         ? |          13.325  |
+-----------+------------------+

您很可能希望忽略 NULL,而警告只是提醒您这种情况正在发生。

【讨论】:

  • 这正确解释了问题,让我可以愉快地继续忽略警告,因为这正是我所期望的。
  • 尽管我多次对 null 传播感到恼火,但我想我从未真正质疑过它背后的原因。任何可以让我“哇哦”或涉及饼干的答案都得到了我的投票。
  • 我可能已经用谷歌搜索过这个错误几次,但这是迄今为止对这个问题最好的解释,以及它出现的原因和时间。谢谢!
  • 很好的解释!
  • 这解释了“由聚合函数消除”,但没有解释“其他 SET 函数”。你知道这是什么意思吗?
【解决方案2】:

@juergen 提供了两个很好的答案:

  • 使用SET ANSI_WARNINGS OFF 抑制警告
  • 假设您想要包含 NULL 值并将它们视为(例如)使用 select @mindate = min(isnull(d, cast(0 as datetime))) from t

但是,如果您想忽略 d 列为 null 的行并且不关心 ANSI_WARNINGS 选项,那么您可以通过排除 d 设置为 null 的所有行来做到这一点:

select @mindate = min(d) from t where (d IS NOT NULL)

【讨论】:

  • 您的选项 1 有其他副作用。仅当这是单个聚合列时,您的选项 3 才有效。对于select min(d1), min(d2) ,没有可用于执行此操作的 where 子句。你为什么关心这个消息?仅供参考。
  • 谢谢马丁。我的前两个选项只是总结了 juergen 以前的答案,以便形成一个平台来介绍我的选项(3?)。是的,我的建议只有在它是唯一被选择的聚合(最小值、最大值、平均值、总和等)列时才有效,正如 OP 提出的问题一样。这些信息可能只是信息性的,但当我看到它们时,它们总是让我质疑那些打断我手头工作注意力的问题。
【解决方案3】:

我认为您可以忽略此警告,因为您使用了MIN 函数。

“除了 COUNT,聚合函数忽略空值”

请参考Aggregate Functions (Transact-SQL)

【讨论】:

    【解决方案4】:

    min() 在您的情况下应该返回什么作为d 的最低值?

    错误通知您min() 函数没有考虑null 的记录。

    因此,如果它应该忽略 NULL 值并返回最低 现有 日期,那么您可以忽略此警告。

    如果你还想禁止这条语句的警告,那么你可以这样做

    set ansi_warnings off
    select @mindate = min(d) from t
    set ansi_warnings on
    

    如果您希望通过使用默认值来考虑 NULL 值,那么您可以像这样设置默认日期值

    select @mindate = min(isnull(d, cast(0 as datetime)))
    from t
    

    【讨论】:

    • 您建议的“修复”将返回不正确的结果。它将表明最早的日期是1900-01-01(除非碰巧有日期早于数据中的日期)
    • 如果d 具有这两个值,如 '1/1/2001' 和 '1/1/2012' 会发生什么。这将返回 '1/1/1900' 作为最小值?所以如果select * from table where date>@mindate这样做会造成麻烦
    【解决方案5】:

    如果您想进行聚合,请考虑null 值并将结果视为null,您可以使用:

    SELECT IIF(COUNT(N) != COUNT(*), NULL, SUM(N)) as [Sum]
    FROM   (VALUES (NULL),
                   (3),
                   (7)) V(N) 
    

    如果没有给出所有值,则返回 null

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-24
      • 1970-01-01
      • 1970-01-01
      • 2010-10-25
      • 2019-08-23
      相关资源
      最近更新 更多