Por que essa consulta funciona?

37

Eu tenho duas tabelas, table_a (id, nome) e table_b (id), digamos no Oracle 12c.

Por que essa consulta não retorna uma exceção?

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

Pelo que entendi, a Oracle vê isso como

select * from table_a where name = name;

Mas o que eu não entendo é por quê?

eagerMoose
fonte

Respostas:

61

A consulta está sintaticamente correta no SQL, mesmo table_bque não tenha uma namecoluna. O motivo é a resolução do escopo.

Quando a consulta é analisada, primeiro é verificado se table_bhá uma namecoluna. Como isso não acontece, então table_aé verificado. Isso geraria um erro apenas se nenhuma das tabelas tivesse uma namecoluna.

Finalmente, a consulta é executada como:

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

Quanto aos resultados que a consulta forneceria, para cada linha da table_asubconsulta (select name from table_b)- ou (select a.name from table_b b)- é uma tabela com uma única coluna com o mesmo a.namevalor e o mesmo número de linhas table_b. Portanto, se table_btiver 1 ou mais linhas, a consulta será executada como:

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

ou:

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

ou:

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

Se table_bestiver vazio, a consulta não retornará linhas (thnx para @ughai para apontar essa possibilidade).


Esse (o fato de você não receber um erro) é provavelmente o melhor motivo para que todas as referências de coluna sejam prefixadas com o nome / alias da tabela. Se a consulta foi:

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

você teria o erro imediatamente. Quando os prefixos de tabela são omitidos, não é difícil que esses erros ocorram, especialmente em consultas mais complexas e, ainda mais importante, passam despercebidas.

Leia também nos documentos da Oracle: Resolução de nomes em instruções SQL estáticas o exemplo semelhante B-6 em Captura interna e as recomendações nos parágrafos Evitar captura interna em instruções SELECT e DML :

Qualifique cada referência de coluna na instrução com o alias da tabela apropriado.

ypercubeᵀᴹ
fonte
Como você dissecou o funcionamento interno do mecanismo SQL com tanta precisão?
RinkyPinku 16/02
8

Porque

O Oracle executa uma subconsulta correlacionada quando uma subconsulta aninhada faz referência a uma coluna de uma tabela referida a uma instrução pai um nível acima da subconsulta. http://docs.oracle.com/cd/E11882_01/server.112/e41084/queries007.htm#SQLRF52357

Isso significa que, para determinar se a subconsulta está correlacionada, o Oracle deve tentar resolver os nomes na subconsulta, incluindo também o contexto da instrução externa. E para namenão fixado é a única resolução possível.

Serg
fonte
4

Como não há namecampo, table_bo Oracle escolhe o campo table_a. Eu tentei o EXPLAIN PLANmas isso me deu apenas que existe um TABLE ACCESS FULL. Presumo que isso gere algum tipo de produto cartesiano entre as duas tabelas que resultam em uma lista de todos os nomes table_aretornados pela subconsulta.

Marco
fonte
5
"Não há campo de nome no table_b, portanto, o Oracle pega o da table_a." Corrigir. "Presumo que isso gere algum tipo de produto cartesiano". Errado. A consulta possui from table_a where .... Ele retornará todas as linhas, table_aexceto aquelas que namesão nulas.
ypercubeᵀᴹ
11
TABLE ACCESS FULLé apenas uma maneira da Oracle dizer que está fazendo uma varredura seqüencial.
Joishi Bodio
11
Seu PLAN é irrelevante - pode haver indexação com tabelas enormes - presumo que você esteja executando dados de teste?
Vérace 27/06