Esta declaración es legal (en otras palabras, no FROM
se requiere):
SELECT x = 1;
SELECT x = 1 WHERE 1 = 1; -- also try WHERE 1 = 0;
El truco es cuando introduce un nombre de columna que claramente no puede existir. Entonces estos fallan:
SELECT name WHERE 1 = 1;
SELECT x = 1 WHERE id > 0;
Mensaje 207, Nivel 16, Estado 1
Nombre de columna no válido 'nombre'.
Mensaje 207, Nivel 16, Estado 1
Nombre de columna no válido 'id'.
Pero cuando la columna no válida se introduce en algo así como una subconsulta, lo que hace SQL Server cuando no puede encontrar esa columna en el alcance interno de la subconsulta, es transversal a un alcance externo y hace que la subconsulta esté correlacionada con ese alcance externo. Esto devolverá todas las filas, por ejemplo:
SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE 1 = 1);
Porque esencialmente dice:
SELECT * FROM sys.columns WHERE name IN (SELECT sys.columns.name WHERE 1 = 1); /*
^^^^^^^^^^^ -----------
| |
----------------------------------- */
Ni siquiera necesita una WHERE
cláusula en la subconsulta:
SELECT * FROM sys.columns WHERE name IN (SELECT name);
Puede ver que realmente está mirando la tabla de alcance exterior, porque esto:
SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE name > N'x');
Devuelve muchas menos filas (11 en mi sistema).
Esto implica el cumplimiento del estándar sobre el alcance. Puede ver cosas similares cuando tiene dos tablas #temp:
CREATE TABLE #foo(foo int);
CREATE TABLE #bar(bar int);
SELECT foo FROM #foo WHERE foo IN (SELECT foo FROM #bar);
Obviamente, esto debería error, lo correcto, ya que no es foo
en #bar
? No Lo que sucede es que SQL Server dice: "Oh, no encontré un foo
aquí, debes haber querido decir el otro".
Además, en general, lo evitaría NOT IN
. NOT EXISTS
tiene el potencial de ser más eficiente en algunos escenarios, pero lo más importante es que su comportamiento no cambia cuando es posible que la columna objetivo lo sea NULL
. Vea esta publicación para más información .