Sql server 连接空值的更好方法,而不是选择一个神奇的值?

Sql server 连接空值的更好方法,而不是选择一个神奇的值?,sql-server,tsql,sql-server-2008,null,Sql Server,Tsql,Sql Server 2008,Null,我需要连接两个或多或少相同的表(一个是要放入另一个的暂存表数据) 某些列可以为null,当值为null时,我的merge语句中的join不匹配。(这是空值的正常行为。) 问题是,当它们不匹配时,会导致删除并重新创建该行,从而更改实际表中该行的值标识 我知道我可以这样做来加入nulls: on coalesce(target.SomeId, -9999) = coalesce(source.SomeId, -9999) 但我不喜欢挑选一个我希望永远不会被使用的号码。(感觉很脏。) 有没有比使用这

我需要连接两个或多或少相同的表(一个是要放入另一个的暂存表数据)

某些列可以为null,当值为null时,我的merge语句中的join不匹配。(这是空值的正常行为。)

问题是,当它们不匹配时,会导致删除并重新创建该行,从而更改实际表中该行的值标识

我知道我可以这样做来加入nulls:

on coalesce(target.SomeId, -9999) = coalesce(source.SomeId, -9999)
但我不喜欢挑选一个我希望永远不会被使用的号码。(感觉很脏。)

有没有比使用这样的幻数更好的方法在可空列上进行连接?

特殊字符? 否则,您可以尝试:

on (target.SomeId is null OR source.SomeId is null OR target.SomeId = source.SomeId)
让我们接着说:

target.SomeId = source.SomeId
   or (target.SomeId is null and source.SomeId is null)

从概念上讲,这应该是有意义的。也就是说,要么两个值都为null,要么两个值彼此相等。当合并强制进行表扫描时,这也应该表现得更好。我已经将coalesce样式转换为上面的样式,并看到了巨大的性能提升。

假设您指的是不属于连接键的列,那么

...and (isnull(source.ColX, target.ColX) = isnull(target.ColX, source.ColX)
        or (source.ColX is null and target.ColX is null))

应该涵盖所有可能性:如果两个值都不为null或只有一个值不为null,则第一行捕捉,如果两个值都为null,则第二行捕捉。非常难看,但是当你的系统中有太多的空值时就会发生这种情况。

结果很奇怪,它包含由
内部连接产生的行和由
交叉连接产生的行,这些连接是源表和目标表(例如,{s-C,T-C},{s-C,T-D},{s-C,T-E},{s-D,T-C},{s-D,T-D},{S-D,T-E},)

看看这个例子:

DECLARE @Source TABLE (SomeId INT NULL, Name VARCHAR(10) NOT NULL);
DECLARE @Target TABLE (SomeId INT NULL, Name VARCHAR(10) NOT NULL);

INSERT  @Source VALUES (1,'S-A'),(2,'S-B'),(NULL,'S-C'),(NULL,'S-D');
INSERT  @Target VALUES (1,'T-A'),(2,'T-B'),(NULL,'T-C'),(NULL,'T-D'),(NULL,'T-E'),(6,'T-F');

SELECT  s.*, t.*
FROM    @Source s
INNER JOIN @Target t ON s.SomeId = t.SomeId OR s.SomeId IS NULL AND t.SomeId IS NULL;

SELECT  s.*, t.*
FROM    @Source s
INNER JOIN @Target t ON ISNULL(s.SomeId,-9999) = ISNULL(t.SomeId,-9999);
结果:

SomeId      Name       SomeId      Name
----------- ---------- ----------- ----------
1           S-A        1           T-A <- INNER JOIN
2           S-B        2           T-B <- INNER JOIN
NULL        S-C        NULL        T-C <- "CROSS JOIN"
NULL        S-C        NULL        T-D <- "CROSS JOIN"
NULL        S-C        NULL        T-E <- "CROSS JOIN"
NULL        S-D        NULL        T-C <- "CROSS JOIN"
NULL        S-D        NULL        T-D <- "CROSS JOIN"
NULL        S-D        NULL        T-E <- "CROSS JOIN"
SomeId Name SomeId Name
----------- ---------- ----------- ----------

1 S-A 1 T-A我几乎完全使用以下模式

ON EXISTS (SELECT target.SomeId INTERSECT source.SomeId)

从中提取后,第二个条件(检查两侧是否都不为null)似乎是多余的;null值不会与非null值进行比较。这是执行
Object.Equals(target.SomeId,source.SomeId)时Linq2Sql生成的
这很公平,但我敢打赌它会得到优化。@BenThul这看起来很奇怪,但MS添加它肯定有原因。原因很好?哈哈-MS做了很多奇怪的事情,但原因不好-Visual Source Safe、CodePlex、Nokia,所有这些现在都死了,他们说-嗯,他们肯定会出现,还有太多其他的事情希望宇宙能“优化它们”。
ON EXISTS (SELECT target.SomeId INTERSECT source.SomeId)