【问题标题】:How to detect change to update existing values with NULL [duplicate]如何检测更改以使用 NULL 更新现有值 [重复]
【发布时间】:2022-02-10 09:00:43
【问题描述】:

如果现有记录发生更改,我需要更新表。如果记录存在(找到 APK),则在 ID_NUMBER 已更改时更新它。问题是当现有的 TARGET 值不是 NULL 并且 SOURCE 值是 NULL 时。我怎样才能检测到这种情况不相等?

使用 ISNULL() 可以工作,但第二个参数不能出现在数据中。这需要分析所有 NUMERIC 数据。没有它可以吗?在这种情况下,零 (0) 只有当它从未出现在数据中时才能起作用。

UPDATE T SET
    T.f1 = S.f1
FROM TARGET_TABLE T
    INNER JOIN SOURCE_TABLE S
    ON T.APK = S.APK
WHERE
    ISNULL(T.ID_NUMBER,0) <> ISNULL(S.ID_NUMBER,0)
;

这是 TARGET 和 SOURCE 表中 ID_NUMBER 值的可能组合。

Target      Source
======      ======
NULL        NULL
NULL        7       -- should identify as unequal
7           NULL    -- should identify as unequal, BUT DOES NOT
7           7

以下脚本显示了结果。只有第三条语句将现有的 TARGET 值 7 与传入的 SOURCE 值 NULL 进行比较将失败。这是为什么?什么代码可以工作?

SET NOCOUNT ON;
SELECT 3 WHERE ISNULL(NULL, NULL+1) <> ISNULL(NULL,NULL+1);
GO
SELECT 3 WHERE ISNULL(NULL, 7+1) <> ISNULL(7,7+1);
GO
SELECT 3 WHERE ISNULL(7, NULL+1) <> ISNULL(NULL,NULL+1); -- WHY DOES THIS NOT SEE THE INEQUALITY?
GO
SELECT 3 WHERE ISNULL(7, 7+1) <> ISNULL(7,7+1);
GO

示例执行:

1> SET NOCOUNT ON;
2> SELECT 3 WHERE ISNULL(NULL, NULL+1) <> ISNULL(NULL,NULL+1);
3> GO

-----------
1> SELECT 3 WHERE ISNULL(NULL, 7+1) <> ISNULL(7,7+1);
2> GO

-----------
          3
1> SELECT 3 WHERE ISNULL(7, NULL+1) <> ISNULL(NULL,NULL+1); -- WHY DOES THIS NOT SEE THE INEQUALITY?
2> GO

-----------
1> SELECT 3 WHERE ISNULL(7, 7+1) <> ISNULL(7,7+1);
2> GO

-----------
1>

【问题讨论】:

  • 仅供参考 null + 1null

标签: sql sql-server


【解决方案1】:

我强烈建议阅读NULL,因为它代表一个未知值,因此无法比较或添加到另一个值。因此,您必须使用传统的 AND/OR 逻辑将其视为一个单独的案例。

DECLARE @Table1 TABLE (APK int, ID_NUMBER int);
DECLARE @Table2 TABLE (APK int, ID_NUMBER int);

INSERT INTO @Table1 (APK, ID_NUMBER)
  VALUES (1, null), (1, null), (1, 7), (1, 7), (1, 5);

INSERT INTO @Table2 (APK, ID_NUMBER)
  VALUES (1, null), (1, 7), (1, null), (1, 7), (1, 4);

SELECT T.APK, T.ID_NUMBER, S.ID_NUMBER
FROM @Table1 T
INNER JOIN @Table2 S ON T.APK = S.APK
WHERE T.ID_Number <> S.ID_NUMBER
    OR (T.ID_Number IS NULL AND S.ID_NUMBER IS NOT NULL)
    OR (T.ID_Number IS NOT NULL AND S.ID_NUMBER IS NULL);

鉴于我怀疑您已经简化了实际用例,您可能会发现EXCEPT 可以在您的情况下使用,因为EXCEPT(和INTERSECT)在涉及NULL 时执行不同类型的比较s。请参阅here 了解更多信息。

【讨论】:

  • 感谢您的回答。我使用了您提供的 WHERE 子句。链接的文章很有帮助。我不能使用 EXCEPT 因为正在更新的表有一些额外的控制列,例如 UPDATE_DT 和其他。 INTERSECT 看起来同样强大,但由于表没有相同数量的列,我需要手动列出它们。 WHERE 子句很容易从使用正则表达式的简单列名列表生成。谢谢。
【解决方案2】:

请尝试以下解决方案。

它基于通过HASHBYTES() 函数在 CTE 中使用校验和。 此方法适用于表中的 NULL 值和多列。

我添加了 UpdatedOn 列来显示更新的列。

SQL

-- DDL and sample data population, start
DECLARE @Table1 TABLE (APK INT IDENTITY PRIMARY KEY, ID_NUMBER INT, UpdatedOn DATETIMEOFFSET(3));
DECLARE @Table2 TABLE (APK INT IDENTITY PRIMARY KEY, ID_NUMBER INT, UpdatedOn DATETIMEOFFSET(3));

INSERT INTO @Table1 (ID_NUMBER)
  VALUES (null), (null), (7), (7), (5);

INSERT INTO @Table2 (ID_NUMBER)
  VALUES (null), (7), (null), (7), (4);
-- DDL and sample data population, end

WITH source AS
(
    SELECT sp.*, HASHBYTES('sha2_256', xmlcol) as [Checksum] 
    FROM @Table1 sp
    CROSS APPLY (SELECT sp.* FOR XML RAW) x(xmlcol)
), target AS
(
    SELECT sp.*, HASHBYTES('sha2_256', xmlcol) as [Checksum] 
    FROM @Table2 sp
    CROSS APPLY (SELECT sp.* FOR XML RAW) x(xmlcol)
)
UPDATE T 
SET T.ID_NUMBER = S.ID_NUMBER
    , T.UpdatedOn = SYSDATETIMEOFFSET()
FROM TARGET AS T
    INNER JOIN SOURCE AS S
        ON T.APK = S.APK
WHERE T.[Checksum] <> S.[Checksum];

-- test
SELECT * FROM @Table2;

输出

+-----+-----------+--------------------------------+
| APK | ID_NUMBER |           UpdatedOn            |
+-----+-----------+--------------------------------+
|   1 | NULL      | NULL                           |
|   2 | NULL      | 2022-02-09 18:58:10.336 -05:00 |
|   3 | 7         | 2022-02-09 18:58:10.336 -05:00 |
|   4 | 7         | NULL                           |
|   5 | 5         | 2022-02-09 18:58:10.336 -05:00 |
+-----+-----------+--------------------------------+

【讨论】:

    猜你喜欢
    • 2020-01-14
    • 2020-03-12
    • 2018-06-30
    • 2016-09-24
    • 1970-01-01
    • 2017-11-14
    • 2012-02-02
    • 2018-03-14
    • 2018-11-12
    相关资源
    最近更新 更多