【问题标题】:NULL values are excluded. Why?NULL 值被排除在外。为什么?
【发布时间】:2022-03-24 08:32:21
【问题描述】:

这是关于我在 Microsoft Sql Server 中发现的一种奇怪行为。如果我错了,请纠正我。

SELECT COUNT(*) FROM TABLEA 
WHERE [Column1] IS NULL;

这将返回 30018 行。

CREATE VIEW VIEWB AS 
SELECT * FROM TABLEA AS t1 
WHERE t1.[Column1] NOT IN ('Cross/Up sell', 'Renegotiation', 'Renewal')  

如果我检查VIEWB,我在Column1 中找不到NULL

SELECT COUNT(*) FROM VIEWB 
WHERE [Column1] IS NULL;

这将返回 0 行。

为什么?上面的查询排除了 3 个值,但 不应排除 NULL。为什么 Sql Server 女士会这样?我应该预料到这一点吗? 我该如何解决?

【问题讨论】:

  • 这是做什么的:SELECT COUNT(*) FROM TABLEA AS t1 WHERE t1.[Column1] NOT IN ('Cross/Up sell', 'Renegotiation', 'Renewal')
  • 答案,正如 Martin Smith 和 Sumo 所指出的,它应该排除 NULL,因为 NULL 不是一个值
  • 另一个 stackoverfellow 有一个与 NULL 有点相似的问题 stackoverflow.com/questions/11462716/weird-all-inwhere 解释关于 NULL 的规则非常令人困惑。我希望有人可以提及 ANSI SQL 对查询的 NULL 解释有哪些规则
  • @MichaelBuen - 我认为你的回答是错误的。如果列不可为空,则进行该转换仅在语义上等效。 SQL Server 不会像 OP 所期望的那样返回任何行。 (编辑刚刚注意到你在这些方面给出了第二个答案)
  • @MartinSmith 关于NOT ININ 的NULL,我已经知道它的规则了。这是关于ALL 的规则让我绊倒,IIRC,ALL 在内部翻译为MAX,因此关于MAX 上的空值规则(空值被丢弃)也适用于ALL .. 或者我想.对 3 RDBMS 进一步测试,发现有区别,3 RDBMS 与MAX 一致,但与ALL 不一致

标签: sql sql-server sql-server-2008


【解决方案1】:

这实际上是 SQL Server 在将 NULL 视为值时常犯的错误。默认情况下,它被视为 UNKNOWN,如 here 所述。因此,在您看来,您还需要包含一个OR t1.[Column1] IS NULL

您可以通过调用SET ANSI_NULLS OFF 来更改此行为。但是,不建议使用此功能,因为@Martin Smith 指出该功能已被弃用。

但是,这不是 SQL Server 特定的问题。它是ANSI SQL standard 的一部分。

【讨论】:

  • SET ANSI_NULLS OFF 的完整性值得一提,但已被弃用,并且在文档中有以下警告。 Avoid using this feature in new development work, and plan to modify applications that currently use this feature.
【解决方案2】:

SQL 使用three valued logic

t1.[Column1] NOT IN ('Cross/Up sell', 'Renegotiation', 'Renewal') 

等价于

t1.[Column1] <> 'Cross/Up sell' AND  
t1.[Column1] <> 'Renegotiation' AND 
t1.[Column1] <>  'Renewal')

t1.[Column1] is NULL 时,此表达式的计算结果为UNKNOWN 而不是TRUE,因此不会返回这些行。

只有在NOT IN 子句的计算结果为空集时才会返回NULL NOT IN ( ... )

【讨论】:

  • VIEWB 应该显示 Column1 不是三个值之一的所有记录。意思是,它应该包括 column1 为 NULL 的记录,但显然它没有这样做。
  • @MikeFulton - 当 column1 为 NULL 时,无论它是否是这些值之一,它都被视为未知。 SQL 使用TRUE/FALSE/UNKNOWNWHERE 子句仅返回谓词计算结果为 true 的行。
【解决方案3】:

最好的答案就是在 where 子句中使用以下条件

ISNULL(t1.[Column1],'') 不在('交叉/向上销售'、'重新协商'、'续订')

【讨论】:

    【解决方案4】:

    另一个在处理nulls时要小心的例子

    我只是同意 Sumo - 为什么不直接将视图更改为:

    CREATE VIEW VIEWB AS 
    SELECT * FROM TABLEA AS t1 
    WHERE 
        t1.[Column1] NOT IN ('Cross/Up sell', 'Renegotiation', 'Renewal')  
        OR
        t1 IS NULL 
    

    我添加到SQL FIDDLE的替代方法可能是以下内容

    CREATE VIEW VIEWB AS 
    SELECT * FROM TABLEA AS t1 
    WHERE 
        1 = CASE 
              WHEN ISNULL(t1.[Column1],'x') NOT IN ('Cross/Up sell', 'Renegotiation', 'Renewal') THEN 1
              ELSE 0
            END
    

    【讨论】:

      【解决方案5】:

      在处理空值时还有另一种方法。我们可以使用

      coalesce(t1.[Column1], ' ') not in ('Cross/Up sell', 'Renegotiation', 'Renewal')
      

      【讨论】:

      • 这种方法有什么好处?你能edit你的答案包括细节吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 2016-08-30
      相关资源
      最近更新 更多