Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Clause WHERE vs ON lors de l'utilisation de JOIN

Faites juste attention à la différence avec les jointures externes. Une requête où un filtre b.IsApproved (sur le tableau de droite, Bar) est ajouté au ON condition du JOIN :

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId); 

N'est PAS revient à placer le filtre dans WHERE clause :

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId)
WHERE (b.IsApproved = 1); 

Puisque pour les jointures externes 'échouées' à Bar (c'est-à-dire lorsqu'il n'y a pas de b.BarId pour un f.BarId ), cela laissera b.IsApproved comme NULL pour toutes ces lignes de jointure ayant échoué, et ces lignes seront alors filtrées.

Une autre façon de voir cela est que pour la première requête, LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId) renverra toujours les lignes de la table LEFT, puisque LEFT OUTER JOIN garantit que les lignes de la table LEFT seront renvoyées même si la jointure échoue. Cependant, l'effet de l'ajout de (b.IsApproved = 1) à la LEFT OUTER JOIN la condition est de NULL sur toutes les colonnes de table de droite lorsque (b.IsApproved = 1) est faux, c'est-à-dire selon les mêmes règles normalement appliquées à un LEFT JOIN condition sur (b.BarId = f.BarId) .

Mettre à jour :Pour compléter la question posée par Conrad, la LOJ équivalente pour un filtre OPTIONAL serait :

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId)
WHERE (b.IsApproved IS NULL OR b.IsApproved = 1);

c'est-à-dire le WHERE la clause doit considérer à la fois la condition d'échec de la jointure (NULL) et le filtre doit être ignoré, et où la jointure réussit et le filtre doit être appliqué. (b.IsApproved ou b.BarId pourrait être testé pour NULL )

J'ai rassemblé ici un SqlFiddle qui montre les différences entre les différents emplacements du b.IsApproved filtre relatif au JOIN .