web-dev-qa-db-fra.com

Pourquoi cette requête fonctionne-t-elle?

J'ai deux tables, table_a (id, nom) et table_b (id), disons sur Oracle 12c.

Pourquoi cette requête ne renvoie-t-elle pas d'exception?

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

D'après ce que je comprends, Oracle voit cela comme

select * from table_a where name = name;

Mais ce que je ne comprends pas, c'est pourquoi?

36
eagerMoose

La requête est syntaxiquement correcte SQL même si table_b n'a pas de colonne name. La raison en est la résolution de la portée.

Lorsque la requête est analysée, il est d'abord vérifié si table_b a une colonne name. Comme ce n'est pas le cas, alors table_a est vérifié. Cela ne générerait une erreur que si aucune des tables n'avait de colonne name.

Enfin, la requête est exécutée comme:

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

Quant aux résultats de la requête, pour chaque ligne de table_a, la sous-requête (select name from table_b) - ou (select a.name from table_b b) - est un tableau avec une seule colonne avec le même a.name valeur et autant de lignes que table_b. Donc si table_b a 1 ou plusieurs lignes, la requête s'exécute comme:

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 ;

Si table_b est vide, la requête ne retournera aucune ligne (merci à @ughai pour avoir pointé cette possibilité).


Cela (le fait que vous n'obtenez pas d'erreur) est probablement la meilleure raison pour laquelle toutes les références de colonne doivent être précédées du nom/alias de la table. Si la requête était:

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

vous auriez tout de suite eu l'erreur. Lorsque les préfixes de table sont omis, il n'est pas difficile que de telles erreurs se produisent, en particulier dans les requêtes plus complexes, et plus important encore, passent inaperçues.

Lire aussi dans Oracle docs: Resolution of Names in Static SQL Statements l'exemple similaire B-6 dans Capture interne et les recommandations dans les paragraphes Éviter la capture interne dans les paragraphes SELECT et DML :

Qualifiez chaque référence de colonne dans l'instruction avec l'alias de table approprié.

60
ypercubeᵀᴹ

Parce que

Oracle effectue une sous-requête corrélée lorsqu'une sous-requête imbriquée fait référence à une colonne d'une table référencée à une instruction parent un niveau au-dessus de la sous-requête. http://docs.Oracle.com/cd/E11882_01/server.112/e41084/queries007.htm#SQLRF52357

Cela signifie que pour déterminer si la sous-requête est corrélée, Oracle doit essayer de résoudre les noms dans la sous-requête, y compris le contexte de l'instruction externe. Et pour name non préfixé, c'est la seule résolution possible.

8
Serg

Il n'y a pas de champ name dans table_b donc Oracle prend celui de table_a. J'ai essayé le EXPLAIN PLAN mais cela m'a donné seulement qu'il y a TABLE ACCESSFULL. Je suppose que cela générera une sorte de produit cartésien entre les deux tables, ce qui donnera une liste de tous les noms dans table_a est retourné par la sous-requête.

4
Marco