Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Cláusula WHERE vs ON ao usar JOIN


Apenas tome cuidado com a diferença com junções externas. Uma consulta em que um filtro de b.IsApproved (na tabela à direita, Bar) é adicionado ao ON condição do JOIN :
SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId); 

É NÃO o mesmo que colocar o filtro em WHERE cláusula:
SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId)
WHERE (b.IsApproved = 1); 

Como para junções externas 'falhadas' para Bar (ou seja, onde não há b.BarId para um f.BarId ), isso deixará b.IsApproved como NULL para todas essas linhas de junção com falha, e essas linhas serão filtradas.

Outra maneira de ver isso é que, para a primeira consulta, LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId) sempre retornará as linhas da tabela LEFT, pois LEFT OUTER JOIN garante que as linhas da tabela LEFT serão retornadas mesmo se a junção falhar. No entanto, o efeito de adicionar (b.IsApproved = 1) para o LEFT OUTER JOIN na condição é NULL qualquer coluna da tabela à direita quando (b.IsApproved = 1) é falso, ou seja, de acordo com as mesmas regras normalmente aplicadas a um LEFT JOIN condição em (b.BarId = f.BarId) .

Atualizar :Para completar a pergunta feita por Conrad, o LOJ equivalente para um filtro OPCIONAL seria:
SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId)
WHERE (b.IsApproved IS NULL OR b.IsApproved = 1);

ou seja, o WHERE A cláusula precisa considerar tanto a condição se a junção falha (NULL) e o filtro deve ser ignorado e onde a junção for bem-sucedida e o filtro deve ser aplicado. (b.IsApproved ou b.BarId pode ser testado para NULL )

Eu coloquei um SqlFiddle aqui que demonstra as diferenças entre os vários posicionamentos do b.IsApproved filtro relativo ao JOIN .