¿Por qué funciona esta consulta?

37

Tengo dos tablas, table_a (id, name) y table_b (id), digamos en Oracle 12c.

¿Por qué esta consulta no devuelve una excepción?

select * from table_a where name in (select name from table_b);

Por lo que entiendo, Oracle ve esto como

select * from table_a where name = name;

Pero lo que no entiendo es ¿por qué?

ansioso
fuente

Respuestas:

61

La consulta es SQL sintácticamente correcto incluso si table_bno tiene una namecolumna. La razón es la resolución del alcance.

Cuando se analiza la consulta, primero se verifica si table_btiene una namecolumna. Como no lo hace, entonces table_ase verifica. Lanzaría un error solo si ninguna de las tablas tuviera una namecolumna.

Finalmente la consulta se ejecuta como:

select a.* 
from table_a  a
where a.name in (select a.name 
                 from table_b  b
                );

En cuanto a los resultados que daría la consulta, por cada fila de table_ala subconsulta (select name from table_b), o bien (select a.name from table_b b), es una tabla con una sola columna con el mismo a.namevalor y tantas filas como table_b. Entonces, si table_btiene 1 o más filas, la consulta se ejecuta como:

select a.* 
from table_a  a
where a.name in (a.name, a.name, ..., a.name) ;

o:

select a.* 
from table_a  a
where a.name = a.name ;

o:

select a.* 
from table_a  a
where a.name is not null ;

Si table_bestá vacío, la consulta no devolverá filas (gracias a @ughai por señalar esa posibilidad).


Eso (el hecho de que no obtiene un error) es probablemente la mejor razón por la que todas las referencias de columna deben tener como prefijo el nombre / alias de la tabla. Si la consulta fue:

select a.* from table_a where a.name in (select b.name from table_b); 

Habría recibido el error de inmediato. Cuando se omiten los prefijos de tabla, no es difícil que ocurran tales errores, especialmente en consultas más complejas, y aún más importante, pasan desapercibidas.

Lea también en documentos de Oracle: Resolución de nombres en declaraciones estáticas de SQL, el ejemplo similar B-6 en Captura interna y las recomendaciones en los párrafos Evitar captura interna en las declaraciones SELECT y DML :

Califique cada referencia de columna en la declaración con el alias de tabla apropiado.

ypercubeᵀᴹ
fuente
¿Cómo diseccionó el funcionamiento interno del motor SQL con tanta precisión?
RinkyPinku
8

Porque

Oracle realiza una subconsulta correlacionada cuando una subconsulta anidada hace referencia a una columna de una tabla referida a una declaración principal un nivel por encima de la subconsulta. http://docs.oracle.com/cd/E11882_01/server.112/e41084/queries007.htm#SQLRF52357

Significa que para determinar si la subconsulta está correlacionada, Oracle debe intentar resolver los nombres en la subconsulta, incluido el contexto de la declaración externa también. Y para nameno prefijado es la única resolución posible.

Serg
fuente
4

No hay namecampo en, table_basí que Oracle toma el de table_a. Probé el EXPLAIN PLANpero esto me dio solo que hay un TABLE ACCESS FULL. Supongo que esto generará algún tipo de producto cartesiano entre ambas tablas que dará como resultado que la subconsulta table_adevuelva una lista de todos los nombres .

Marco
fuente
55
"No hay un campo de nombre en la tabla_b, por lo que Oracle toma el de la tabla_a". Correcto. "Supongo que esto generará algún tipo de producto cartesiano". Incorrecto. La consulta tiene from table_a where .... Devolverá todas las filas, table_aexcepto las que namesean nulas.
ypercubeᵀᴹ
1
TABLE ACCESS FULLes solo la forma en que Oracle le dice que está haciendo un escaneo secuencial.
Joishi Bodio
1
Su PLAN es irrelevante; puede que haya indexado con tablas enormes. ¿Supongo que está ejecutando datos de prueba?
Vérace