【问题标题】:SQL JOIN match NULL column valuesSQL JOIN 匹配 NULL 列值
【发布时间】:2018-12-14 04:05:36
【问题描述】:

我在 MS SQL Server 2012 中使用JOIN 删除一个表中与另一个表中的记录匹配的记录

DELETE t1
FROM Table1 t1
JOIN Table2 t2
    ON 
    t1.[Column1] = t2.[Column1] 
    AND t1.[Column2] = t2.[Column2] 
    AND t1.[Column3] = t2.[Column3] 

但是,如果两个表中的列都包含null,则它们不会被匹配并被删除。如果两列都包含null,我如何修改查询以匹配记录,而不添加对null的特定检查

DELETE t1
FROM Table1 t1
JOIN Table2 t2
    ON 
    t1.[Column1] = t2.[Column1] OR (t1.[Column1] is null and t2.[Column1] is null)
    AND t1.[Column2] = t2.[Column2] OR (t1.[Column2] is null and t2.[Column2] is null)
    AND t1.[Column3] = t2.[Column3] OR (t1.[Column3] is null and t2.[Column3] is null)

【问题讨论】:

  • 使用 ISNULL 将空值更改为某个默认值,例如对于 INT,如果为 NULL,则默认为 0

标签: sql join sql-server-2012 null sql-delete


【解决方案1】:

这是一个真正的问题,因为 SQL Server 没有NULL-safe 比较运算符。 ANSI 标准运算符是IS NOT DISTINCT FROM

OR 的问题在于它排除了索引的使用。 ISNULL() 的问题是一样的。因此,如果您的表有任何大小,您应该避免使用它们。

您可以做的一件事是将值设置为默认值。我不知道哪些默认值可以避免现有值,但这可能看起来像:

update table1
    set column1 = coalesce(column1, ''),  -- for strings
        column2 = coalesce(column2, -1),  -- for numbers
        column3 = coalesce(column3, cast('1900-01-01' as date))  -- for dates
    where column1 is null or column2 is null or column3 is null;

您需要在两张桌子上都这样做。然后,您可以在删除后恢复 NULL 值。

实际上,在 SQL Server 中,您可以添加计算列:

alter table1 add column1_notnull as (coalesce(column1, '')) persisted;  -- or whatever

然后您可以在它们上创建索引:

create index idx_table1_columns_123_notnull on table1(column1_notnull, column2_notnull, column3_notnull);

然后重复table2

然后您的第一个查询将起作用(当然使用_notnull 列)并利用索引来提高性能。

【讨论】:

    【解决方案2】:

    您可以使用SET ANSI_NULLS OFF 使= 将两个nulls 视为相等。

    【讨论】:

    • 从来不知道ANSI NULLS 设置在做什么,谢谢。来自我的 +1。
    • 这可以在每个脚本的基础上完成吗?我刚刚在我的脚本中尝试了它并得到了'ANSI' is not a recognized SET option.
    • @webworm 很抱歉打错字了 - 它应该是 SET ANSI_NULLS OFFANSINULLS 之间有一个下划线。
    • 我在脚本中使用了SET ANSI_NULLS OFF,虽然没有发生错误,但它仍然与包含null 值的列不匹配
    【解决方案3】:

    可以尝试以下方法:

    DELETE t1
    FROM Table1 t1
    JOIN Table2 t2
        ON 
        Isnull(t1.[Column1],'') = isnull(t2.[Column1],'')
        AND isnull(t1.[Column2],'') = isnull(t2.[Column2],'')
        AND isnull(t1.[Column3],'') = isnull(t2.[Column3],'');
    

    【讨论】:

    • 其实一般规则是使用'',因为它几乎可以转换成任何类型。
    • 谢谢。由于某种原因,我只是假设这些列是数字的。我更正了答案。
    猜你喜欢
    • 1970-01-01
    • 2019-07-13
    • 2011-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-29
    • 2017-04-12
    相关资源
    最近更新 更多