Cette déclaration est légale (en d'autres termes, aucune FROM
n'est requise):
SELECT x = 1;
SELECT x = 1 WHERE 1 = 1; -- also try WHERE 1 = 0;
L'astuce consiste à introduire un nom de colonne qui ne peut clairement pas exister. Donc, ceux-ci échouent:
SELECT name WHERE 1 = 1;
SELECT x = 1 WHERE id > 0;
Msg 207, niveau 16, état 1
Nom de colonne non valide 'nom'.
Msg 207, niveau 16, état 1
Nom de colonne non valide «id».
Mais lorsque la colonne non valide est introduite dans quelque chose comme une sous-requête, ce que fait SQL Server lorsqu'il ne peut pas trouver cette colonne dans la portée interne de la sous-requête, est traversé vers une portée externe et rend la sous-requête corrélée à cette portée externe. Cela renverra toutes les lignes, par exemple:
SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE 1 = 1);
Parce qu'il dit essentiellement:
SELECT * FROM sys.columns WHERE name IN (SELECT sys.columns.name WHERE 1 = 1); /*
^^^^^^^^^^^ -----------
| |
----------------------------------- */
Vous n'avez même pas besoin d'une WHERE
clause dans la sous-requête:
SELECT * FROM sys.columns WHERE name IN (SELECT name);
Vous pouvez voir qu'il regarde vraiment la table de portée externe, car ceci:
SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE name > N'x');
Renvoie beaucoup moins de lignes (11 sur mon système).
Cela implique le respect de la norme sur la portée. Vous pouvez voir des choses similaires lorsque vous avez deux tables #temp:
CREATE TABLE #foo(foo int);
CREATE TABLE #bar(bar int);
SELECT foo FROM #foo WHERE foo IN (SELECT foo FROM #bar);
De toute évidence, cela devrait être une erreur, non, car il n'y a pas d' foo
entrée #bar
? Nan. Ce qui se passe, c'est que SQL Server dit: "oh, je n'ai pas trouvé un foo
ici, vous devez avoir voulu dire l'autre."
Aussi, en général, j'éviterais NOT IN
. NOT EXISTS
a le potentiel d'être plus efficace dans certains scénarios, mais plus important encore, son comportement ne change pas lorsqu'il est possible que la colonne cible puisse l'être NULL
. Voir cet article pour plus d'informations .