Tenho duas tabelas, table_a (id, name) e table_b (id), digamos no Oracle 12c.
Por que esta 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ê?
A consulta é um SQL sintaticamente correto, mesmo que
table_b
não tenha umaname
coluna. O motivo é a resolução do escopo.Quando a consulta é analisada, primeiro é verificado se
table_b
há umaname
coluna. Uma vez que não, entãotable_a
é verificado. Isso lançaria um erro apenas se nenhuma das tabelas tivesse umaname
coluna.Por fim, a consulta é executada como:
Quanto aos resultados que a consulta daria, para cada linha de
table_a
, a subconsulta(select name from table_b)
- ou(select a.name from table_b b)
- é uma tabela com uma única coluna com o mesmoa.name
valor e tantas linhas quantotable_b
. Portanto, setable_b
tiver 1 ou mais linhas, a consulta será executada como:ou:
ou:
Se
table_b
estiver vazio, a consulta não retornará nenhuma linha (obrigado @ughai por apontar essa possibilidade).Isso (o fato de você não receber um erro) é provavelmente o melhor motivo pelo qual todas as referências de coluna devem ser prefixadas com o nome/alias da tabela. Se a consulta foi:
você teria o erro imediatamente. Quando os prefixos da tabela são omitidos, não é difícil que tais erros aconteçam, principalmente em consultas mais complexas e, mais importante ainda, que passem despercebidos.
Leia também nos documentos do 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 Evitando captura interna em instruções SELECT e DML :
Porque
Isso significa que, para determinar se a subconsulta está correlacionada, o Oracle deve tentar resolver os nomes na subconsulta, incluindo o contexto da instrução externa também. E para sem prefixo
name
é a única resolução possível.Não há
name
campo em,table_b
então o Oracle pega o detable_a
. Eu tentei,EXPLAIN PLAN
mas isso me deu apenas que existe um arquivoTABLE ACCESS
FULL
. Presumo que isso gerará algum tipo de produto cartesiano entre as duas tabelas que resultará em uma lista de todos os nomestable_a
retornados pela subconsulta.