加入空值比选择神奇值更好的方法?

时间:2011-10-03 16:09:41

标签: sql-server tsql sql-server-2008 null

我需要加入两个或多或少相同的表(一个是另一个临时表数据)。

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

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

我知道我可以做这样的事情来加入空值:

on coalesce(target.SomeId, -9999) = coalesce(source.SomeId, -9999)

但我不想挑出一个我希望永远不会被使用的号码。 (感觉很脏。)

是否有更好的方法在可空列上进行连接而不是使用像这样的幻数?

6 个答案:

答案 0 :(得分:5)

让我们一起来看看:

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

从概念上讲,这应该是有道理的。也就是说,两个值都为空或两个值彼此相等。由于合并强制进行表扫描,因此这也应该表现得更好。我已经将合并风格转换为上述风格并且看到了巨大的性能提升。

答案 1 :(得分:3)

我几乎只使用以下模式

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

Paul White's blog post here提取后。

答案 2 :(得分:0)

ON ((target.SomeId IS NULL) AND (source.SomeId IS NULL)) 
OR ((target.SomeId IS NOT NULL) AND (source.SomeId IS NOT NULL) 
AND (target.SomeId = source.SomeId)))

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:0)

结果很奇怪,包含INNER JOIN产生的行和来自源表和目标表的CROSS JOINNULL ID的行(例如{SC,TC},{SC ,TD},{SC,TE},{SD,TC},{SD,TD},{SD,TE},)。

看看这个例子:

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"

答案 5 :(得分:-1)

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

on (target.SomeId is null OR source.SomeId is null OR target.SomeId = source.SomeId)