2016-01-04 7 views
6

Ich verstehe das Verhalten in diesem Fall nicht. Nach meinem Verständnis sollte eine Abfrage mit einer ungültigen Unterabfrage zu einem Fehler führen. Aber in diesem Beispiel gibt es einige Zeilen zurück.Abfrage mit gebrochenen Sub-Select sollte zu einem Fehler führen, aber Zeilen

-Test-Daten:

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; 

Arbeiten wie erwartet:

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 

Aber die folgende Abfrage wird auch Zeilen abrufen, offensichtlich durch den "Test_ID2" -Spalte aus dem "test_values" nehmen - Tabelle und nicht von der "test_lookup" -Tabelle wie in der Unterabfrage angegeben und obwohl NOT-Aliase für innere und äußere Teile nicht verwendet werden.

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 das OP einen vollständigen Testfall, einschließlich Erstellen von Tabellen und Einfügen von Anweisungen. Ich bin nicht sicher, welche zusätzlichen Informationen Sie erwarten, dass das OP zu ihrer Frage hinzufügt! – Boneist

+0

Ich fragte eine ähnliche Frage hier http://stackoverflow.com/questions/34774242/force-outer-select-to-fail-if-the-inner-select-contains-an-invalid-identifier. Wenn Sie fragen, wie Sie dieses Verhalten ändern können ... scheint das nicht möglich zu sein. –

+0

Ja. Es benutzt den richtigen (aber längeren) Code und alles ist gut Ding;) – evilive

Antwort

6

Der Grund ist, weil, wenn eine unaliased Spalte in der Unterabfrage ist nicht vorhanden, aber in der äußeren Abfrage existiert, Oracle vorausgesetzt, dass Sie von der äußeren Abfrage auf die Spalte verweisen.

mit Aliasnamen, die Abfrage Sie sind verwirrt würde wie folgt aussehen:

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

Hoffentlich das macht die Dinge klarer?

Das Problem, das Sie sehen, ist ein sehr gutes Beispiel dafür, warum Sie Ihre Spalten immer mit der Tabelle versehen sollten, aus der sie kamen - es macht es viel einfacher, die Abfrage für einen Start zu pflegen!

+0

Vielen Dank. In der Tat bin ich immer noch erstaunt, dass es so funktioniert.Wenn Sie nicht an eine select-, sondern an eine irgendwie gespeicherte delete-Anweisung denken, können Sie versehentlich Zeilen aus der Tabelle "A" löschen, indem Sie die Spalten der Tabelle "B" ändern und die Anweisung selbst nicht berühren ** urghs **. Ok, werde jetzt Aliase verwenden, wenn immer mehr als eine Tabelle verwendet wird;) – evilive

+1

@evilive funktioniert so, weil korrelierte Unterabfragen - z. 'select * from table1 t1 wo existiert (wählen Sie null aus table2 t2 wobei t1.col1 = t2.col1);'. I.e. Der Umfang der äußeren Abfrage erstreckt sich auf die oberste Ebene aller darin enthaltenen Unterabfragen. Wenn die Abfrage explizit angibt, welche Spalten verwendet werden, muss Oracle erraten, aus welcher Tabelle die Spalte stammt. Und Requisiten, um einen anderen Fall zu entdecken, um die Verwendung von Aliasen zu unterstützen! – Boneist

+2

@evilive: Dies ist eigentlich nicht spezifisch für Oracle. So ist Namensauflösung definiert, um im SQL-Standard –

4

Wenn Ihre "defekte" Abfrage als Unterabfrage verwendet wird, kann sie immer noch auf die Tabellenspalten der äußeren Abfrage verweisen. das ist notwendig, damit die Korrelation funktioniert. Es nimmt die tst_id2 Spalte von der test_values Tabelle auf. Wenn beide Tabellen dieselbe Spalte hätten, würde die innere Tabelle Vorrang haben, aber das ist hier nicht der Fall.

From the documentation:

Oracle unqualifizierte Spalten in der Unterabfrage löst, indem sie in der Unterabfrage in den Tabellen suchen benannt und dann in den in der übergeordneten Anweisung benannten Tabellen.

Sie können sehen, was passiert, indem Sie Tabellenaliase hinzufügen; dies immer noch Fehler:

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 

Aber das funktioniert:

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

Es wird test_values Spalte explizit mit (über die tv alias); Ihre ursprüngliche Abfrage hat das gleiche getan, aber implizit.

+0

Dank zu arbeiten, war Bonein ein wenig schneller – evilive

+3

@evilive - nicht das erste Mal, und wahrscheinlich nicht zum letzten Mal ... Ich werde das hier trotzdem als verlassen es ist * leicht * anders und hat einen Doc-Link * 8-) –

+1

@AlexPoole Hurra für Doc-Links! * {;-D (p.s. Frohes Neues Jahr!) – Boneist