Questa affermazione è legale (in altre parole, non FROM
è richiesto):
SELECT x = 1;
SELECT x = 1 WHERE 1 = 1; -- also try WHERE 1 = 0;
Il trucco è quando si introduce un nome di colonna che chiaramente non può esistere. Quindi questi falliscono:
SELECT name WHERE 1 = 1;
SELECT x = 1 WHERE id > 0;
Messaggio 207, livello 16, stato 1
Nome colonna 'nome' non valido.
Messaggio 207, livello 16, stato 1
Nome colonna "id" non valido.
Ma quando la colonna non valida viene introdotta in qualcosa di simile a una sottoquery, cosa fa SQL Server quando non riesce a trovare quella colonna nell'ambito interno della sottoquery, si attraversa un ambito esterno e rende la sottoquery correlata a tale ambito esterno. Ciò restituirà tutte le righe, ad esempio:
SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE 1 = 1);
Perché essenzialmente sta dicendo:
SELECT * FROM sys.columns WHERE name IN (SELECT sys.columns.name WHERE 1 = 1); /*
^^^^^^^^^^^ -----------
| |
----------------------------------- */
Non è nemmeno necessaria una WHERE
clausola nella sottoquery:
SELECT * FROM sys.columns WHERE name IN (SELECT name);
Puoi vedere che sta davvero guardando la tabella con ambito esterno, perché questo:
SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE name > N'x');
Restituisce molte meno righe (11 sul mio sistema).
Ciò comporta l'adesione allo standard sull'ambito. Puoi vedere cose simili quando hai due tabelle #temp:
CREATE TABLE #foo(foo int);
CREATE TABLE #bar(bar int);
SELECT foo FROM #foo WHERE foo IN (SELECT foo FROM #bar);
Ovviamente, questo dovrebbe errore, a destra, dal momento che non v'è foo
in #bar
? No. Quello che succede è che SQL Server dice "oh, non ho trovato un foo
qui, devi aver inteso l'altro".
Inoltre, in generale, eviterei NOT IN
. NOT EXISTS
ha il potenziale per essere più efficiente in alcuni scenari, ma ancora più importante, il suo comportamento non cambia quando è possibile che la colonna target sia NULL
. Vedi questo post per maggiori informazioni .