如何处理合并SQL的WHEN MATCHED中的空值?

var*_*ble -2 sql sql-server

MERGE TARGET T
USING SOURCE S
ON T.ID=S.ID

WHEN MATCHED AND (S.NAME<>T.NAME OR S.DOB<>T.DOB)
THEN UPDATE
SET T.NAME=S.NAME, T.DOB=S.DOB;
Run Code Online (Sandbox Code Playgroud)

以上无法处理源端或目标端 name/dob 为空的情况。因为与 NULL 的比较返回 false。这要怎么处理呢?

例子:

COALESCE(S.NAME,'')<>COALESCE(T.NAME,'')
Run Code Online (Sandbox Code Playgroud)

或者

COALESCE(S.NAME,0)<>COALESCE(T.NAME,0)
Run Code Online (Sandbox Code Playgroud)

或者

NULLIF(S.NAME,'')<>NULLIF(T.NAME,'')
Run Code Online (Sandbox Code Playgroud)

Dai*_*Dai 5

就像这样:

MERGE INTO destTable WITH (HOLDLOCK) AS tgt
USING srcRelation AS src ON
    /* Only specify PK columns here: */
    tgt.Pk1 = src.Pk1
    AND
    tgt.Pk2 = src.Pk2

WHEN MATCHED AND EXISTS (

    /*
    Only specify "data" columns here; these are the columns which are also included in the UPDATE SET clause below.
    Don't include GENERATED, rowversion, PRIMARY KEY, and other "non-data" columns
    */

    SELECT tgt.Col1, tgt.Col2, tgt.Col3, etc
    EXCEPT
    SELECT src.Col1, src.Col2, src.Col3, etc
)
THEN UPDATE SET
    tgt.Col1 = src.Col1,
    tgt.Col2 = src.Col2,
    tgt.Col3 = src.Col3

WHEN NOT MATCHED BY TARGET THEN etc...;
Run Code Online (Sandbox Code Playgroud)

具体来说,就您的情况而言:

MERGE INTO "target" WITH (HOLDLOCK) AS tgt
USING "source" AS src ON
    tgt."ID" = src."ID"
WHEN MATCHED AND EXISTS (
    SELECT tgt."Name"
    EXCEPT
    SELECT src."Name"
)
THEN UPDATE SET
    tgt."Name" = src."Name";
Run Code Online (Sandbox Code Playgroud)

  • @variable 和使用 `coalesce` 可能会导致查询无法控制,即无法使用索引。因此这是一个更好的解决方案。(您确实询问了最好的方法:)) (3认同)
  • @variable 正如其他人在他们的评论回复中指出的那样:**`COALESCE` 在这种情况下是不合适的**,因为它并不表明 `''` 与 `NULL` 不同,更不用说引入其他歧义了wrt 数据类型。要点是:**你不应该**在“MERGE ... WHEN MATCHED AND...”子句中使用“COALSECE”(也不应该使用“ISNULL”)。- 而 `EXISTS ( SELECT src... EXCEPT SELECT tgt... )` 在 T-SQL 中是惯用的并且_按预期工作_。 (2认同)