Usando una declaración IN que parece que no debería funcionar, pero de alguna manera se ejecuta
Frecuentes
Visto 67 equipos
0
Estaba depurando la consulta de otra persona y encontré una declaración muy extraña que parecía que no debería funcionar en absoluto. Destilé esto de la consulta original a esto:
DECLARE @c TABLE (id INT);
DECLARE @y TABLE (name VARCHAR(50) PRIMARY KEY);
INSERT INTO @c VALUES (1);
SELECT
c.*
FROM
@c c
WHERE
id NOT IN (
SELECT
id
FROM
@y
WHERE
id IS NOT NULL);
Pero, ¿cómo puede funcionar esto? Agregué la restricción de que id NO ES NULO, pero eliminar esto no parece cambiar el comportamiento.
También puede eliminar la CLAVE PRIMARIA en la tabla temporal, ¿¡esto fue solo una jugada para mostrar que el plan de ejecución usa el índice de alguna manera!?
Esta es la versión "lite":
DECLARE @c TABLE (id INT);
DECLARE @y TABLE (name VARCHAR(50));
INSERT INTO @c VALUES (1);
SELECT * FROM @c WHERE id NOT IN (SELECT id FROM @y);
Cuando se ejecuta en SQL Server 2008 R2, devolverá una respuesta de 1.
3 Respuestas
3
No estoy seguro de por qué, pero cuando la subconsulta llama a columnas incorrectas y es esencialmente inválida, la declaración de selección externa aún se ejecuta. El predicado in/not in con la subconsulta se ignora esencialmente. He visto esto antes, pero nunca supe por qué. Sin embargo, eché un vistazo y encontré este enlace:
Donde alguien menciona lo siguiente:
Estoy de acuerdo en que el comportamiento es confuso, pero es un comportamiento estándar ANSI para la resolución de nombres de columna en diferentes ámbitos.
Consulte este artículo de KB para obtener más información: http://support.microsoft.com/kb/298674
La razón por la que esto me confundió aún más es que usé el nombre de la columna que no existe en ya sea table y, por lo tanto, obtuvo el error "esperado" (nombre de columna no válido). Por lo tanto, si está utilizando un nombre de columna que no se puede resolver en el ámbito interno (SELECCIONE Table1Id DE Table2) pero que se puede resolver en ámbito externo (SELECCIONE * DE Table1 DONDE...), se resolverá y enlazará en ese ámbito .
Esto parece confuso en el ejemplo que dio, pero se aplica la misma lógica si usa dicha construcción en la cláusula WHERE de la consulta interna. Por ejemplo, considere la consulta interna con este aspecto:
... (SELECCIONE Table2Id DESDE Table2 DONDE Table2Id = Table1Id)
La consulta por sí sola fallará, pero funcionará, ya que Table1Id estará vinculado a Table1 en la consulta externa.
contestado el 19 de mayo de 14 a las 15:05
Excelente, entonces es un error, pero no "realmente" un error ya que es parte del estándar ANSI. genial :D- Richard Hansell
Ciertamente me atrapó un par de veces en el pasado :) - ScubaManDan
2
En una subconsulta, si el nombre de la columna que menciona no existe en las tablas que forman la subconsulta, SQL buscará las columnas en la consulta adjunta (a menos que haya proporcionado un alias).
Por lo tanto, la id
mencionado en su subconsulta es en realidad el id
columna de la @c
mesa.
Así que eso id
El valor se devolverá una vez por cada fila que devuelva la subconsulta, pero dado que la subconsulta devuelve un conjunto vacío, esto significa que el NOT IN
no considera valores y por lo tanto tiene éxito.
Esta es la razón por la que es un muy buen hábito usar alias de tabla en las subconsultas; de esa manera, si accidentalmente nombra una columna que solo existe en una tabla externa, obtendrá un error en lugar de un resultado inesperado:
SELECT * FROM @c WHERE id NOT IN (SELECT y.id FROM @y y);
produce un error.
contestado el 19 de mayo de 14 a las 15:05
0
En primera SELECT id FROM @y
no hay un solo valor en @y
. Porque no hay valor en @y
, la id
desde @c
no será devuelto por la subconsulta. Por lo que puedo decir, el servidor SQL que devuelve 1 es correcto. Sólo una vez que se insertan uno o más registros en @y
El servidor SQL no devolverá nada.
contestado el 19 de mayo de 14 a las 15:05
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas sql sql-server tsql sql-server-2008-r2 or haz tu propia pregunta.
el hecho de que la identificación no existe en @y, si tuviera que ejecutar SELECT id FROM @y, daría un error. - Richard Hansell
¡La identificación no se selecciona de la tabla @y, sino de la tabla @c! - martennis