Meilleur moyen de join les valeurs nulles que de choisir une valeur magique?

J'ai besoin de joindre deux tables qui sont plus ou less les mêmes (l'une est une table de transfert de données pour aller dans l'autre).

Certaines des colonnes sont nullables et lorsque les valeurs sont null, la jointure dans mon instruction de fusion ne correspond pas. (Ceci est un comportement normal pour les valeurs nulles.)

Le problème est que, lorsqu'elles ne correspondent pas, la ligne est supprimée et recréée, en modifiant l'identité de la ligne dans la table réelle.

Je sais que je peux faire quelque chose comme ça pour join les nulls:

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

Mais je n'aime pas avoir à choisir un chiffre qui, je l'espère, ne sera jamais utilisé. (Il se sent sale.)

Y at-il un meilleur moyen de faire une jointure sur une colonne nullable que d'utiliser un nombre magique comme ça?

Allons-y avec ceci:

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

Conceptuellement, cela devrait avoir un sens. Autrement dit, les deux valeurs sont nulles ou les deux valeurs sont égales les unes aux autres. Cela devrait également fonctionner mieux car le coalesce force un balayage de table. J'ai converti le style coalesce à celui ci-dessus et j'ai vu d'énormes gains de performance.

J'utilise presque exclusivement le motif suivant

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

après l'avoir pris sur le blog de Paul White ici .

 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))) 

En supposant que vous voulez dire des colonnes qui ne font pas partie de la key de jointure, alors

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

devrait couvrir toutes les possibilités: la première ligne attrape si les deux valeurs ne sont pas nulles ou qu'une seule valeur n'est pas nulle, et la deuxième ligne attrape si les deux sont nuls. Assez moche, mais c'est ce qui arrive quand vous avez trop de zéros dans votre système.

Le résultat est étrange et contient des lignes issues de INNER JOIN et des lignes résultent d'une CROSS JOIN entre des NULL IDs de la table source et cible (ex: {SC, TC}, {SC, TD}, {SC, TE}, {SD, TC}, {SD, TD}, {SD, TE},).

Regardez cet exemple:

 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); 

Résultats:

 SomeId Name SomeId Name ----------- ---------- ----------- ---------- 1 SA 1 TA <- INNER JOIN 2 SB 2 TB <- INNER JOIN NULL SC NULL TC <- "CROSS JOIN" NULL SC NULL TD <- "CROSS JOIN" NULL SC NULL TE <- "CROSS JOIN" NULL SD NULL TC <- "CROSS JOIN" NULL SD NULL TD <- "CROSS JOIN" NULL SD NULL TE <- "CROSS JOIN" 

Caractères spéciaux? Sinon, vous pouvez essayer:

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