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 WHEREclausola 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'è fooin #bar? No. Quello che succede è che SQL Server dice "oh, non ho trovato un fooqui, devi aver inteso l'altro".
Inoltre, in generale, eviterei NOT IN. NOT EXISTSha 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 .