Perché questa query funziona?


37

Ho due tabelle, table_a (id, nome) e table_b (id), diciamo su Oracle 12c.

Perché questa query non restituisce un'eccezione?

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

Da quello che ho capito, Oracle lo vede come

select * from table_a where name = name;

Ma quello che non capisco è perché?

Risposte:


61

La query è SQL sintatticamente corretto anche se table_bnon ha una namecolonna. Il motivo è la risoluzione dell'ambito.

Quando la query viene analizzata, viene prima verificato se table_bha una namecolonna. Dal momento che non lo fa, quindi table_aviene controllato. Avrebbe generato un errore solo se nessuna delle tabelle avesse una namecolonna.

Infine la query viene eseguita come:

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

Per quanto riguarda i risultati che la query darebbe, per ogni riga di table_a, la sottoquery (select name from table_b)- o (select a.name from table_b b)- è una tabella con una singola colonna con lo stesso a.namevalore e tante righe quante table_b. Quindi, se table_bha 1 o più righe, la query viene eseguita come:

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 ;

Se table_bè vuoto, la query non restituirà alcuna riga (grazie a @ughai per indicare quella possibilità).


Questo (il fatto che non si ottiene un errore) è probabilmente il motivo migliore per cui tutti i riferimenti di colonna devono essere preceduti dal nome / alias della tabella. Se la query era:

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

avresti subito subito l'errore. Quando si omettono i prefissi delle tabelle, non è difficile che si verifichino tali errori, soprattutto nelle query più complesse, e ancora più importanti, inosservate.

Leggi anche nei documenti Oracle: Risoluzione dei nomi nelle istruzioni SQL statiche l'esempio simile B-6 in Acquisizione interna e le raccomandazioni nei paragrafi Evitare l'acquisizione interna in Dichiarazioni SELECT e DML :

Qualificare ogni riferimento di colonna nell'istruzione con l'alias di tabella appropriato.


Come hai analizzato i meccanismi interni del motore SQL in modo così accurato?
RinkyPinku,

8

Perché

Oracle esegue una query secondaria correlata quando una query secondaria nidificata fa riferimento a una colonna di una tabella riferita a un'istruzione parent un livello sopra la query secondaria. http://docs.oracle.com/cd/E11882_01/server.112/e41084/queries007.htm#SQLRF52357

Significa per determinare se la subquery è correlata Oracle deve cercare di risolvere i nomi nella subquery incluso anche il contesto dell'istruzione esterna. E per namenon prefissati è l'unica risoluzione possibile.


4

Non c'è namecampo in table_bcosì Oracle prende quello da table_a. Ho provato il EXPLAIN PLANma questo mi ha dato solo che c'è un TABLE ACCESS FULL. Presumo che questo genererà un qualche tipo di prodotto cartesiano tra le due tabelle che risulta in un elenco di tutti i nomi table_arestituiti dalla sottoquery.


5
"Non esiste un campo nome in table_b, quindi Oracle prende quello da table_a." Corretta. "Presumo che questo genererà una sorta di prodotto cartesiano". Sbagliato. La query ha from table_a where .... Restituirà tutte le righe table_atranne quelle namenulle.
ypercubeᵀᴹ

1
TABLE ACCESS FULLè solo il modo di Oracle di dirti che sta eseguendo una scansione sequenziale.
Joishi Bodio,

1
Il tuo PIANO è irrilevante - potrebbe esserci l'indicizzazione con tabelle enormi - suppongo che tu stia eseguendo i dati di test?
Vérace,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.