【问题标题】:Is there a way to simplify a NULL compare of 2 values有没有办法简化 2 个值的 NULL 比较
【发布时间】:2021-09-01 08:33:15
【问题描述】:

这是我的简化陈述

SELECT ...
FROM tab1 AS i FULL OUTER JOIN tab2 AS d ON i.[Id]=d.[Id] 
WHERE d.[Data]<>i.[Data] OR 
    (d.[Data] IS NULL AND i.[Data] IS NOT NULL) OR 
    (d.[Data] IS NOT NULL AND i.[Data] IS NULL)

我想获取所有的条目

  1. i.[Data] 与 d.[Data] 不同
  2. 表 i 或 d 中至少有一个值不为空

所以我不想看到记录 was 和 i 和 d 包含相同的数据或者都是 NULL。

我的陈述看起来又长又复杂。有没有更简单的方法?

使用ISNULL(d.[Data],'')&lt;&gt;ISNULL(i.[Data],'') 适用于文本,但不适用于DATETIME(0) 列。

我的陈述适用于所有类型。

【问题讨论】:

  • 您可以在第二次比较中只使用正确类型的常量 - 我认为您应该知道您的列类型?
  • 不幸的是,他们仍然没有实现标准IS DISTINCT FROM,这正是您在单个运算符中想要的。但它只是在标准中出现了两年,所以你能期待什么..
  • @Damien_The_Unbeliever 查看我的回答和Paul White

标签: sql-server tsql


【解决方案1】:

可以,您也可以让优化器识别它。

Paul White has this little ditty:

WHERE NOT EXISTS (
    SELECT d.[Data]
    INTERSECT
    SELECT i.[Data])

这是因为INTERSECT 处理空值的语义。这说的是“子查询中是否有 no 行由值 B 和值 B 组成”,只有当它们是不同的值或一个为空而另一个不为空时才会满足。如果两者都是空值,就会有一行空值。


如果您检查 XML 查询计划(不是 SSMS 中的图形查询计划),您会看到它一直编译到 d.[Data] &lt;&gt; i.[Data],但它使用的运算符将具有 CompareOp="IS" 而不是 EQ

查看完整计划here

计划的相关部分是:

                <Predicate>
                  <ScalarOperator ScalarString="@t1.[i] as [t1].[i] = @t2.[i] as [t2].[i]">
                    <Compare CompareOp="IS">
                      <ScalarOperator>
                        <Identifier>
                          <ColumnReference Table="@t1" Alias="[t1]" Column="i" />
                        </Identifier>
                      </ScalarOperator>
                      <ScalarOperator>
                        <Identifier>
                          <ColumnReference Table="@t2" Alias="[t2]" Column="i" />
                        </Identifier>
                      </ScalarOperator>
                    </Compare>
                  </ScalarOperator>
                </Predicate>

我发现优化器以这种方式工作得很好,而不是 EXISTS / EXCEPT


我强烈建议您投票支持Azure Feedback 以实施适当的运营商

【讨论】:

  • 但这不是解决方案和完整的查询。那么 WHER d.[Data]i.[data] AND EXISTS (SELECT d.[Data] INTERSECT SELECT i.[Data]) 正确吗?
  • 不,您可以省略第一部分,EXISTS 将完成整个比较。已经澄清
【解决方案2】:

您可以简化为:

SELECT ...
FROM ...
WHERE d.[Data] <> i.[Data]
OR IIF(d.[Data] IS NULL, 0, 1) = IIF(i.[Data] IS NULL, 1, 0)

live demo

【讨论】:

  • 在 T-SQL 中,您只能对“布尔值”进行 AND、OR 和 NOT 等逻辑运算。无法直接比较“布尔值”。
  • @peter 谢谢。不那么整洁,但现在已修复。
  • 那不会优化得这么好
猜你喜欢
  • 2013-07-09
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 2014-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多