SQL Server 2008 R2, mas o comportamento provável também é encontrado em todas as outras versões do SQL Server.
Isso pode parecer óbvio, mas para mim parece um bug.
A consulta a seguir fornece resultados inesperados, aqui está a configuração:
CREATE TABLE #Base (
Key1 int,
RefDate date
)
CREATE TABLE #JoinTable (
Key1 int,
RefDate date
)
INSERT INTO #Base
SELECT 1, '2012-05-05'
UNION
SELECT 2, '2013-06-06'
UNION
SELECT 3, '2014-07-07'
UNION
SELECT 4, '2015-08-08'
UNION
SELECT 5, '2016-09-09'
INSERT INTO #JoinTable
SELECT 4, '2012-05-05'
UNION
SELECT 5, '2013-06-06'
UNION
SELECT 6, '2014-07-07'
UNION
SELECT 7, '2015-08-08'
UNION
SELECT 8, '2016-09-09'
A consulta a seguir é executada conforme esperado, retornando as 3 linhas que ocorrem apenas na tabela base:
SELECT *
FROM #Base b
LEFT OUTER JOIN #JoinTable j ON b.Key1 = j.Key1
WHERE j.Key1 IS NULL
Agora, gostaria de restringir as linhas àquelas anteriores a 1º de janeiro de 2014. Pelo que entendi, posso seguir as duas abordagens abaixo, ambas devem ser perfeitamente viáveis:
SELECT b.*
FROM #Base b
LEFT OUTER JOIN #JoinTable j ON b.Key1 = j.Key1 AND b.RefDate < '2014-01-01'
WHERE j.Key1 IS NULL
SELECT b.*
FROM #Base b
LEFT OUTER JOIN #JoinTable j ON b.Key1 = j.Key1
WHERE j.Key1 IS NULL AND b.RefDate < '2014-01-01'
No entanto, apenas a 2ª consulta retorna os dados que desejo. O primeiro parece ignorar a condição de junção adicionada após o AND na linha de junção.
Por quê?
(link do SQL Fiddle aqui )
Não é um bug, é como
LEFT JOIN
funciona.retornaria todas as linhas,
b
independentemente da condição de junção. A condição de junção define/limita apenas de quais linhas seriam retornadasj
.Você pode pensar nisso da seguinte forma:
#Base
.#Base
encontre todas as linhas#JoinTable
que satisfaçam os critérios de junção (b.Key1 = j.Key1 AND b.RefDate < '2014-01-01'
). Não poderia haver tais linhas em#JoinTable
, neste caso returnNULLs
. Observe que os critérios de junção não filtram#Base
, eles filtram apenas#JoinTable
.Quando você coloca
b.RefDate < '2014-01-01'
,WHERE
então você está filtrando#Base
.A primeira junção de consulta é lida como "join table #jointable only if #Base.RefDate < '2014-01-01'" que retornará linhas de #Base with RefDate >= '2014-01-01' além de registros de #Base que não possui linha relacionada em #JoinTable.
A segunda consulta é lida como "retorna todas as linhas de #Base datadas < '2014-01-01' que não possuem nenhuma linha relacionada em #JoinTable".
Acho que você deseja substituir uma consulta não existente por junção esquerda .. onde é nulo. Você deve verificar a consulta original, qual dessas condições:
... and not exists (select null from #JoinTable j where j.Key = b.Key and b.RefDate < '2014-01-01')
para a primeira consultaou
... and not exists (select null from #JoinTable j where j.Key = b.Key) and b.RefDate < '2014-01-01'
para a segunda consulta.Concluindo, não é um bug.
HTH