2016-01-04 22 views
6

Non capisco il comportamento in questo caso. A mio avviso, una query con una sotto-query non valida dovrebbe generare un errore. Ma in questo esempio restituisce alcune righe.La query con sub-selezione interrotta dovrebbe generare un errore ma restituisce righe

Test-dati:

create table test_values (tst_id number, tst_id2 number, tst_value varchar2(10)); 

create table test_lookup (tst_id number, tst_value varchar2(10)); 

insert into test_values(tst_id, tst_id2, tst_value) values (1, 2, 'a'); 
insert into test_values(tst_id, tst_id2, tst_value) values (1, 2, 'b'); 
insert into test_values(tst_id, tst_id2, tst_value) values (2, 2,'c'); 
insert into test_values(tst_id, tst_id2, tst_value) values (2, 2,'d'); 

insert into test_lookup(tst_id, tst_value) values (1, 'findMe'); 

commit; 

funziona come previsto:

select * from test_values where tst_id in (select tst_id from test_lookup where tst_value = 'findMe'); 

/* 
    TST_ID TST_ID2 TST_VALUE 
---------- ---------- ---------- 
     1   2 b   
     1   2 a 
*/ 

select tst_id2 from test_lookup where tst_value = 'findMe'; 
--ORA-00904: "TST_ID2": invalid identifier 

Ma la seguente query è anche recupero cime, ovviamente prendendo il -column "test_id2" dai "test_values" - tabella e non dalla tabella "test_lookup" come indicato nella sottoquery e sebbene NON utilizzi alias per le parti interne ed esterne.

select * from test_values where tst_id in (select tst_id2 from test_lookup where tst_value = 'findMe'); 

/* 
    TST_ID TST_ID2 TST_VALUE 
---------- ---------- ---------- 
     2   2 c   
     2   2 d   
*/ 
+2

@vmachan l'OP ha pubblicato un testcase completo, incluse le istruzioni create table e insert. Non sono sicuro di quali informazioni extra ti aspetti dall'OP da aggiungere alla loro domanda! – Boneist

+0

Ho posto una domanda simile qui http://stackoverflow.com/questions/34774242/force-outer-select-to-fail-if-the-inner-select-taintain-an-invalid-identifier. Se stai chiedendo come modificare questo comportamento ... sembra che tu non possa. –

+0

Sì. Questo usa il codice corretto (ma più lungo) e tutto va bene;) – evilive

risposta

6

La ragione è che quando una colonna unaliased non esiste nella sottoquery ma esiste nella query esterna, Oracle presuppone che si riferisce alla colonna dalla query esterna.

con gli alias, la query siete confusi su sarebbe simile:

select * 
from test_values tv 
where tv.tst_id in (select tv.tst_id2 
        from test_lookup tl 
        where tl.tst_value = 'findMe'); 

spera, che rende le cose più chiare?

Il problema che stai vedendo è un ottimo esempio del perché dovresti sempre etichettare le tue colonne con quale tabella provengono - rende molto più semplice mantenere la query per cominciare!

+0

Grazie. In effetti sono ancora stupito che funzioni così.Pensando non a una selezione, ma a un'istruzione di cancellazione memorizzata in qualche modo, potresti eliminare inavvertitamente le righe dalla tabella "A" alterando le colonne della tabella "B" e senza nemmeno toccare la frase stessa ** urghs **. Ok, userai ora gli alias ogni volta che usi più di una tabella;) – evilive

+1

@evilive funziona così a causa di sottoquery correlate - ad es. 'select * dalla tabella1 t1 dove esiste (selezionare null dalla tabella2 t2 dove t1.col1 = t2.col1);'. Cioè l'ambito della query esterna si estende al livello più alto di qualsiasi subquery al suo interno. Quindi, se la query è esplicita su quali colonne sta utilizzando, Oracle deve indovinare da quale tabella proviene la colonna. E oggetti di scena per individuare un altro caso per supportare l'uso di alias! – Boneist

+2

@evilive: in realtà non è specifico per Oracle. Ecco come viene definita la risoluzione dei nomi per funzionare nello standard SQL –

4

Quando la query "interrotta" viene utilizzata come sottoquery, può comunque fare riferimento alle colonne della tabella della query esterna; è necessario che la correlazione funzioni. Sta raccogliendo la colonna dalla tabella test_values. Se entrambe le tabelle avessero la stessa colonna, il tavolo interno avrebbe la precedenza, ma non è questo il caso.

From the documentation:

Oracle risolve colonne non qualificati nella subquery, cercando nelle tabelle citati nella subquery e poi nelle tabelle denominate nella dichiarazione genitore.

È possibile visualizzare ciò che accade aggiungendo alias di tabella; questo errore ancora:

select * from test_values tv where tst_id in (
    select tl.tst_id2 from test_lookup tl where tl.tst_value = 'findMe'); 

ORA-00904: "TL"."TST_ID2": invalid identifier 

Ma questo funziona:

select * from test_values tv where tst_id in (
    select tv.tst_id2 from test_lookup tl where tl.tst_value = 'findMe'); 

Si esplicitamente usando test_values colonna (tramite i tv alias); la tua query originale stava facendo lo stesso, ma implicitamente.

+0

Grazie a, Boneist è stato un po 'più veloce – evilive

+3

@evilive - non è la prima volta, e probabilmente non l'ultima volta ... Lascerò questo qui comunque come è * leggermente * diverso e ha un collegamento doc * 8-) –

+1

@AlexPoole evviva per i link doc! * {;-D (p.s. Happy New Year!) – Boneist