Esta declaração é legal (em outras palavras, não FROM
é necessária):
SELECT x = 1;
SELECT x = 1 WHERE 1 = 1; -- also try WHERE 1 = 0;
O truque é quando você introduz um nome de coluna que claramente não pode existir. Portanto, estes falham:
SELECT name WHERE 1 = 1;
SELECT x = 1 WHERE id > 0;
Mensagem 207, Nível 16, Estado 1
Nome da coluna inválido 'name'.
Mensagem 207, Nível 16, Estado 1
Nome da coluna inválido 'id'.
Mas quando a coluna inválida é introduzida em algo como uma subconsulta, o que o SQL Server faz quando não consegue encontrar essa coluna no escopo interno da subconsulta, é direcionado para um escopo externo e torna a subconsulta correlacionada a esse escopo externo. Isso retornará todas as linhas, por exemplo:
SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE 1 = 1);
Porque é essencialmente dizendo:
SELECT * FROM sys.columns WHERE name IN (SELECT sys.columns.name WHERE 1 = 1); /*
^^^^^^^^^^^ -----------
| |
----------------------------------- */
Você nem precisa de uma WHERE
cláusula na subconsulta:
SELECT * FROM sys.columns WHERE name IN (SELECT name);
Você pode ver que realmente está olhando para a tabela com escopo externo, porque isso:
SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE name > N'x');
Retorna muito menos linhas (11 no meu sistema).
Isso envolve a adesão ao padrão sobre o escopo. Você pode ver coisas semelhantes quando tiver duas tabelas #temp:
CREATE TABLE #foo(foo int);
CREATE TABLE #bar(bar int);
SELECT foo FROM #foo WHERE foo IN (SELECT foo FROM #bar);
Obviamente, isso deve erro, direito, uma vez que não é foo
em #bar
? Não. O que acontece é que o SQL Server diz: "Ah, eu não encontrei um foo
aqui, você deve ter pensado no outro".
Além disso, em geral, eu evitaria NOT IN
. NOT EXISTS
tem o potencial de ser mais eficiente em alguns cenários, mas o mais importante é que seu comportamento não muda quando é possível que a coluna de destino possa ser NULL
. Veja este post para mais informações .