sql >> Base de Datos >  >> RDS >> Sqlserver

Cláusula WHERE vs ON al usar JOIN

Solo tenga cuidado con la diferencia con las uniones externas. Una consulta donde un filtro de b.IsApproved (en la tabla de la derecha, Bar) se agrega a ON condición de JOIN :

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

NO lo mismo que colocar el filtro en el WHERE cláusula:

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

Dado que para uniones externas 'fallidas' a Bar (es decir, donde no hay b.BarId para un f.BarId ), esto dejará b.IsApproved como NULL para todas esas filas de combinación fallidas, y estas filas luego se filtrarán.

Otra forma de ver esto es que para la primera consulta, LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId) siempre devolverá las filas de la tabla IZQUIERDA, ya que LEFT OUTER JOIN garantiza que se devolverán las filas de la tabla IZQUIERDA incluso si falla la combinación. Sin embargo, el efecto de agregar (b.IsApproved = 1) a la LEFT OUTER JOIN con la condición de anular cualquier columna de la tabla derecha cuando (b.IsApproved = 1) es falso, es decir, según las mismas reglas que normalmente se aplican a un LEFT JOIN condición en (b.BarId = f.BarId) .

Actualizar :Para completar la pregunta de Conrad, el LOJ equivalente para un filtro OPCIONAL sería:

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

es decir, el WHERE la cláusula debe considerar tanto la condición de si la unión falla (NULL) y el filtro debe ignorarse, y donde la combinación tiene éxito y debe aplicarse el filtro. (b.IsApproved o b.BarId podría probarse para NULL )

He reunido un SqlFiddle aquí que demuestra las diferencias entre las distintas ubicaciones de b.IsApproved filtro relativo a JOIN .