Warum funktioniert diese Abfrage?

37

Ich habe zwei Tabellen, table_a (id, name) und table_b (id), sagen wir auf Oracle 12c.

Warum gibt diese Abfrage keine Ausnahme zurück?

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

Nach meinem Verständnis sieht Oracle dies als

select * from table_a where name = name;

Aber was ich nicht verstehe, ist warum?

eagerMoose
quelle

Antworten:

61

Die Abfrage ist syntaktisch korrektes SQL, auch wenn table_bkeine nameSpalte vorhanden ist. Der Grund ist die Auflösung des Bereichs.

Beim Analysieren der Abfrage wird zunächst geprüft, ob table_beine nameSpalte vorhanden ist. Da dies nicht der Fall ist, table_awird geprüft. Es würde nur dann einen Fehler auslösen, wenn keine der Tabellen eine nameSpalte hätte.

Schließlich wird die Abfrage ausgeführt als:

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

Was die Ergebnisse table_aangeht, so ist die Abfrage für jede Zeile der Unterabfrage (select name from table_b)- oder (select a.name from table_b b)- eine Tabelle mit einer einzelnen Spalte mit demselben a.nameWert und so vielen Zeilen wie möglich table_b. Wenn also table_beine oder mehrere Zeilen vorhanden sind, wird die Abfrage wie folgt ausgeführt:

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

oder:

select a.* 
from table_a  a
where a.name = a.name ;

oder:

select a.* 
from table_a  a
where a.name is not null ;

Wenn table_bleer, gibt die Abfrage keine Zeilen zurück (danke an @ughai, um auf diese Möglichkeit hinzuweisen).


Das (die Tatsache, dass Sie keinen Fehler erhalten) ist wahrscheinlich der beste Grund, dass allen Spaltenreferenzen der Tabellenname / Alias ​​vorangestellt werden sollte. Wenn die Abfrage lautete:

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

Sie hätten den Fehler sofort bekommen. Wenn Tabellenpräfixe weggelassen werden, ist es nicht schwierig, dass solche Fehler auftreten, insbesondere bei komplexeren Abfragen, und noch wichtiger, dass sie unbemerkt bleiben.

Lesen Sie auch in Oracle-Dokumenten: Auflösung von Namen in statischen SQL-Anweisungen das ähnliche Beispiel B-6 in Inner Capture und die Empfehlungen in den Absätzen Vermeiden von Inner Capture in SELECT- und DML-Anweisungen :

Qualifizieren Sie jede Spaltenreferenz in der Anweisung mit dem entsprechenden Tabellenalias.

ypercubeᵀᴹ
quelle
Wie haben Sie das Innenleben der SQL-Engine so genau analysiert?
RinkyPinku
8

weil

Oracle führt eine korrelierte Unterabfrage durch, wenn eine verschachtelte Unterabfrage eine Spalte aus einer Tabelle referenziert, die eine Ebene über der Unterabfrage auf eine übergeordnete Anweisung verweist. http://docs.oracle.com/cd/E11882_01/server.112/e41084/queries007.htm#SQLRF52357

Dies bedeutet, dass Oracle versuchen muss , Namen in der Unterabfrage einschließlich des Kontexts der äußeren Anweisung aufzulösen , um festzustellen, ob die Unterabfrage korreliert ist . Und für Unfixed ist namees die einzig mögliche Auflösung.

Serg
quelle
4

Es gibt kein nameFeld in, table_balso nimmt Oracle das von table_a. Ich habe das versucht EXPLAIN PLANaber das gab mir nur das es eine gibt TABLE ACCESS FULL. Ich gehe davon aus, dass dies eine Art kartesisches Produkt zwischen beiden Tabellen erzeugt, das eine Liste aller Namen table_aergibt, in denen die Unterabfrage zurückgibt.

Marco
quelle
5
Msgstr "Es gibt kein Namensfeld in table_b, also nimmt Oracle das von table_a." Richtig. "Ich gehe davon aus, dass dies zu einer Art kartesischem Produkt führen wird." Falsch. Die Abfrage hat from table_a where .... Es werden alle Zeilen mit table_aAusnahme derjenigen, namedie null sind, zurückgegeben.
Ypercubeᵀᴹ
1
TABLE ACCESS FULLDies ist nur die Art und Weise, wie Oracle Ihnen mitteilt, dass ein sequentieller Scan durchgeführt wird.
Joishi Bodio
1
Ihr PLAN ist irrelevant - es kann durchaus zu einer Indizierung mit großen Tabellen kommen - ich gehe davon aus, dass Sie mit Testdaten arbeiten?
Vérace