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 .
Je l'ai reproduit en 2016 avec un exemple simplifié:
Il apparaît que c2 et c3 sont évalués pour chaque ligne.
la source
Dans SQL Server SELECT, la syntaxe ne nécessite pas de section FROM. Si vous omettez FROM, l'instruction select utilisera la table "factice" qui a une ligne et aucune colonne. Donc
renverra une ligne si l'expression est vraie et aucune ligne lorsqu'elle est fausse.
la source
select c
etc
n'existe pas dans un objet extérieur. Je suis d' accord queFROM
n'est pas nécessaire, mais la mécanique en jeu ici lorsque vous nommez explicitement une colonne qui fait exister dans un champ extérieur sont certainement différent de celui d' une table factice, et si vous ne fournissez pas une constante pour une colonne qui ne existe, vous obtenez une erreur d'exécution, donc pas de table factice là non plus. La table factice peut entrer en jeu dans d'autres scénarios, mais pas lorsque la référence se trouve dans une table de sous-requête / dérivée.SELECT 'x' AS c
est un scénario complètement différent de celui des PO, qui vient de le direSELECT c
. Dans une sous-requête / table dérivée.