web-dev-qa-db-ja.com

このクエリはなぜ機能するのですか?

2つのテーブルtable_a(id、name)とtable_b(id)があります。Oracle12cについて考えてみましょう。

このクエリが例外を返さないのはなぜですか?

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

私が理解していることから、オラクルはこれを

select * from table_a where name = name;

しかし、私が得られないのはなぜですか?

36
eagerMoose

table_bname列がない場合でも、クエリは構文的に正しいSQLです。その理由は、スコープの解決です。

クエリが解析されると、最初にtable_bname列があるかどうかがチェックされます。ないので、table_aがチェックされます。どちらのテーブルにもname列がない場合にのみ、エラーがスローされます。

最後に、クエリは次のように実行されます。

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

クエリが返す結果については、table_aのすべての行について、サブクエリ(select name from table_b)-または(select a.name from table_b b)-は、同じa.name値を持つ単一の列を持つテーブルですtable_bと同じ行数。したがって、table_bに1つ以上の行がある場合、クエリは次のように実行されます。

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

または:

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

または:

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

table_bが空の場合、クエリは行を返しません(その可能性を示すために@ughaiにthnx)。


これ(エラーが発生しないという事実)は、すべての列参照の前にテーブル名/エイリアスを付ける必要がある最も良い理由です。クエリが次の場合:

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

すぐにエラーが発生します。テーブルプレフィックスが省略されている場合、特により複雑なクエリでそのようなミスが発生することは難しくありません。

Oracle docs:Static SQL Statementsでの名前の解決Inner captureの同様の例B-6と推奨事項も読んでくださいSELECTおよびDMLステートメント段落での内部キャプチャの回避:

ステートメントの各列参照を適切なテーブルエイリアスで修飾します。

60
ypercubeᵀᴹ

なぜなら

ネストされたサブクエリが、サブクエリの1レベル上の親ステートメントを参照するテーブルの列を参照する場合、Oracleは相関サブクエリを実行します。 http://docs.Oracle.com/cd/E11882_01/server.112/e41084/queries007.htm#SQLRF52357

これは、サブクエリが相関しているかどうかを判断するために、Oraclemustが外部ステートメントコンテキストを含むサブクエリの名前も解決しようとすることを意味します。そして、接頭辞のないnameの場合、それが可能な唯一の解決策です。

8
Serg

table_bにはnameフィールドがないため、Oracleはtable_aからフィールドを取得します。私はEXPLAIN PLANを試しましたが、TABLE ACCESSFULLがあることだけがわかりました。これにより、両方のテーブル間にある種のデカルト積が生成され、その結果、table_a内のすべての名前のリストがサブクエリによって返されると思います。

4
Marco