it-swarm.com.de

Warum funktioniert diese Abfrage?

Ich habe zwei Tabellen, table_a (ID, Name) und table_b (ID), sagen wir unter 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?

36
eagerMoose

Die Abfrage ist syntaktisch korrektes SQL, auch wenn table_b hat keine name Spalte. Der Grund ist die Bereichsauflösung.

Wenn die Abfrage analysiert wird, wird zuerst geprüft, ob table_b hat eine name Spalte. Da dies nicht der Fall ist, dann table_a wird geprüft. Es würde nur dann einen Fehler auslösen, wenn keine der Tabellen eine name -Spalte 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 betrifft, würde die Abfrage für jede Zeile von table_a, die Unterabfrage (select name from table_b) - oder (select a.name from table_b b) - ist eine Tabelle mit einer einzelnen Spalte mit demselben a.name Wert und so viele Zeilen wie table_b. Also, wenn table_b hat 1 oder mehr Zeilen, die Abfrage wird ausgeführt als:

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_b ist leer, die Abfrage gibt keine Zeilen zurück (danke an @ughai, um auf diese Möglichkeit hinzuweisen).


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

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

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

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

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

60
ypercubeᵀᴹ

Weil

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

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

8
Serg

Es gibt kein name Feld in table_b, Also nimmt Oracle das von table_a. Ich habe den EXPLAIN PLAN Versucht, aber dies gab mir nur, dass es einen TABLE ACCESSFULL gibt. Ich gehe davon aus, dass dies eine Art kartesisches Produkt zwischen beiden Tabellen erzeugt, das dazu führt, dass eine Liste aller Namen in table_a Von der Unterabfrage zurückgegeben wird.

4
Marco