Pour des raisons indépendantes de ma volonté, j'ai besoin de joindre deux tables et j'ai besoin de valeurs nulles pour correspondre. La meilleure option à laquelle je pouvais penser était de cracher un UUID et de l'utiliser comme valeur de comparaison, mais cela semble moche
SELECT * FROM T1 JOIN T2 ON nvl(T1.SOMECOL,'f44087d5935dccbda23f71f3e9beb491') =
nvl(T2.SOMECOL,'f44087d5935dccbda23f71f3e9beb491')
Comment puis-je faire mieux? C'est sur Oracle si cela importe, et le contexte est une application dans laquelle un lot de données téléchargées par l'utilisateur doit être comparé à un lot de données existantes pour voir si des lignes correspondent. Rétrospectivement, nous aurions dû empêcher l'une des colonnes de jointure des deux ensembles de données de contenir des valeurs nulles, mais nous ne l'avons pas fait et nous devons maintenant vivre avec.
Edit: Pour être clair, je ne suis pas seulement préoccupé par les null. Si les colonnes ne sont pas nulles, je veux qu'elles correspondent à leurs valeurs réelles.
Peut-être que cela fonctionnerait, mais je ne l'ai jamais essayé:
SELECT *
FROM T1 JOIN T2
ON T1.SOMECOL = T2.SOMECOL OR (T1.SOMECOL IS NULL AND T2.SOMECOL IS NULL)
Dans SQL Server, j'ai utilisé:
WHERE (a.col = b.col OR COALESCE(a.col, b.col) IS NULL)
Évidemment pas efficace, à cause de l'OR, mais à moins qu'il n'y ait une valeur réservée, vous pouvez mapper des NULL des deux côtés sans ambiguïté ou pliage, c'est à peu près le mieux que vous puissiez faire (et s'il y en avait, pourquoi NULL était-il même autorisé dans votre conception ... .)
Pour ce type de tâche, Oracle utilise en interne une fonction non documentée sys_op_map_nonnull (), où votre requête deviendrait:
SELECT *
FROM T1 JOIN T2 ON sys_op_map_nonnull(T1.SOMECOL) = sys_op_map_nonnull(T2.SOMECOL)
Sans papiers, alors soyez prudent si vous suivez cette voie.
Vous ne pouvez pas faire mieux, mais le JOIN que vous avez ne fera en aucun cas un "JOIN" réel (il n'y aura aucune corrélation entre T1.SOMECOL et T2.SOMECOL à part qu'ils ont tous deux une valeur NULL pour cela colonne). Fondamentalement, cela signifie que vous ne pourrez pas utiliser un JOIN sur NULL pour voir si les lignes correspondent.
NULL n'est jamais égal à un autre NULL. Comment quelque chose de valeur inconnue peut-il être égal à quelque chose d'autre de valeur inconnue?
Simple, utilisez COALESCE
, qui renverra son premier paramètre non nul:
SELECT * FROM T1 JOIN T2 ON
COALESCE(T1.Field, 'magic string') =
COALESCE(T2.Field, 'magic string')
La seule chose dont vous aurez à vous soucier est que la "chaîne magique" ne peut pas être parmi les valeurs légales pour le champ de jointure dans les deux tableaux.
Voulez-vous vraiment pouvoir rejoindre les tables si une valeur est nulle? Ne pouvez-vous pas simplement exclure les valeurs nulles possibles dans le prédicat de jointure? J'ai du mal à comprendre que les lignes de deux tables peuvent être liées par une valeur nulle. Si vous avez 100 null dans table1.col_a et 100 null dans table2.col_b, vous allez avoir 10000 lignes renvoyées juste pour les lignes avec null. Cela semble incorrect.
Cependant, vous avez dit que vous en aviez besoin. Puis-je suggérer de fusionner la colonne nulle en une chaîne plus petite car les comparaisons de caractères sont relativement coûteuses. Encore mieux, fusionnez les valeurs nulles en un entier si les données dans les colonnes vont être du texte. Ensuite, vous avez des "comparaisons" très rapides et il est peu probable que vous entriez en collision avec des données existantes.
Je pense que vous pouvez toujours utiliser nvl () pour rejoindre:
SELECT *
FROM T1
JOIN T2 ON NVL(T2.COL1,-1)=NVL(T1.COL1,-1);
Mais vous devrez ajouter des index basés sur les fonctions sur les colonnes col1
CREATE INDEX IND_1 ON T1 (NVL(COL1,-1));
CREATE INDEX IND_2 ON T2 (NVL(COL1,-1));
Les index devraient améliorer considérablement la vitesse de la jointure sur NVL (..).
Il suffit de lancer ceci - existe-t-il un moyen de fusionner ces valeurs nulles en une valeur connue, comme une chaîne vide? Ne pas savoir grand-chose sur la disposition de votre table signifie que je ne peux pas être sûr que vous perdrez le sens de cette façon - c'est-à-dire que la chaîne vide représente "l'utilisateur a refusé d'entrer un numéro de téléphone" et NULL étant "nous avons oublié à poser des questions à ce sujet ", ou quelque chose comme ça?
Il y a des chances que ce ne soit pas possible, j'en suis sûr, mais si c'est le cas, vous aurez des valeurs connues à comparer et vous pourrez obtenir une jointure légitime de cette façon.
Pourquoi pas quelque chose comme ça:
SELECT * FROM T1 JOIN T2 ON nvl (T1.SOMECOL, 'null') = nvl (T2.SOMECOL, 'null')
Je ne sais pas pourquoi vous utilisez l'UUID. Vous pouvez utiliser n'importe quelle chaîne non présente dans les colonnes, comme la chaîne "null", par exemple, pour réduire l'empreinte mémoire. Et la solution utilisant nvl
est beaucoup plus rapide que la solution utilisant or ... is null
proposé par Eric Petroelje, par exemple.
N'est-ce pas la même chose que de vérifier la présence de null dans les deux colonnes?
SELECT * FROM T1, T2 WHERE T1.SOMECOL IS NULL and T2.SOMECOL IS NULL
ou
SELECT * FROM T1 CROSS JOIN T2 WHERE T1.SOMECOL IS NULL and T2.SOMECOL IS NULL
@Sarath Avanavu
Celui-ci n'est pas la meilleure approche. Si TA.COL1 conserve la valeur 0 et TB.COL2 est NULL, il joindra ces enregistrements, ce qui n'est pas correct.
SELECT *
FROM TABLEA TA
JOIN TABLEB TB ON NVL(TA.COL1,0)=NVL(TB.COL2,0);
Vous pouvez joindre des valeurs nulles en utilisant decode
:
SELECT * FROM T1 JOIN T2 ON DECODE(T1.SOMECOL, T2.SOMECOL, 1, 0) = 1
decode
traite les valeurs nulles comme égales, donc cela fonctionne sans nombres "magiques". Les deux colonnes doivent avoir le même type de données.
Il ne rendra pas le code le plus lisible, mais probablement encore meilleur que t1.id = t2.id or (t1.id is null and t2.id is null)
Vous pouvez essayer d'utiliser la requête ci-dessous.
SELECT *
FROM TABLEA TA
JOIN TABLEB TB ON NVL(TA.COL1,0)=NVL(TB.COL2,0);