我需要加入两个或多或少相同的表(一个是另一个临时表数据)。
某些列可以为空,当值为null时,我的merge语句中的连接不匹配。 (这是空值的正常行为。)
问题在于,当它们不匹配时会导致删除并重新创建行,更改实际表中行的值标识。
我知道我可以做这样的事情来加入空值:
on coalesce(target.SomeId, -9999) = coalesce(source.SomeId, -9999)
但我不想挑出一个我希望永远不会被使用的号码。 (感觉很脏。)
是否有更好的方法在可空列上进行连接而不是使用像这样的幻数?
答案 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)
答案 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 JOIN
个NULL
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)