Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

WHERE Clausola vs ON quando si utilizza JOIN

Fai solo attenzione alla differenza con i join esterni. Una query in cui è presente un filtro di b.IsApproved (sulla tabella di destra, Bar) viene aggiunto al ON condizione del JOIN :

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

NON come posizionare il filtro in WHERE clausola:

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

Dal momento che per 'falliti' outer join a Bar (ovvero dove non è presente b.BarId per un f.BarId ), questo lascerà b.IsApproved come NULL per tutte queste righe di join non riuscite e queste righe verranno quindi filtrate.

Un altro modo di vedere questo è che per la prima query, LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId) restituirà sempre le righe della tabella LEFT, poiché LEFT OUTER JOIN garantisce che le righe della tabella SINISTRA verranno restituite anche se il join non riesce. Tuttavia, l'effetto dell'aggiunta di (b.IsApproved = 1) al LEFT OUTER JOIN a condizione è di NULL su tutte le colonne della tabella destra quando (b.IsApproved = 1) è falso, cioè secondo le stesse regole normalmente applicate a un LEFT JOIN condizione su (b.BarId = f.BarId) .

Aggiorna :Per completare la domanda posta da Conrad, il LOJ equivalente per un filtro OPZIONALE sarebbe:

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

cioè il WHERE La clausola deve considerare entrambe le condizioni se il join non riesce (NULL) e il filtro deve essere ignorato, e dove il join ha esito positivo e il filtro deve essere applicato. (b.IsApproved o b.BarId potrebbe essere testato per NULL )

Ho messo insieme un SqlFiddle qui che dimostra le differenze tra i vari posizionamenti di b.IsApproved filtro relativo al JOIN .