2016-01-04 3 views
6

この場合の動作はわかりません。私の理解では、無効なサブクエリを持つクエリはエラーになります。しかし、この例では、いくつかの行が返されます。壊れたサブセレクトのクエリはエラーになりますが、行を返します。

テストデータ:予想通り

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; 

作品:

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 

しかし、次のクエリは、また、 "test_values" から "test_id2" - カラムを取ることによって、明らかに、行を取得しています - サブクエリに記述されているように、また内側と外側の部品にエイリアスを使用していないのに、 "test_lookup"テーブルからではありません。非エイリアスの列がサブクエリには存在しませんが、外側のクエリに存在しない場合、Oracleはあなたが外部クエリからのコラムを参照していると仮定しているため

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 OPは、create tableとinsert文を含む完全なテストケースを投稿しました。私はあなたのOPに彼らの質問に追加することを期待している追加情報がわからない! – Boneist

+0

私は似たような質問をここに頼んだ。http://stackoverflow.com/questions/34774242/force-outer-select-to-fail-if-the-inner-select-contains-an-invalid-identifierあなたがこの行動を変える方法を尋ねているなら...それはできないようです。 –

+0

これは適切な(しかしもっと長い)コードを使用し、すべてがうまいものです) – evilive

答えて

6

理由があります。別名を持つ

、あなたが混乱しているクエリは次のようになります。物事が明確になり

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

うまくいけば、?

あなたが見ている問題は、なぜそれらがどのテーブルから来たのかを列に付けなければならない理由の非常に良い例です。

+0

ありがとう。確かに私はそれがこのように動作することに驚いています。選択されたものではなく、何らかの形で保存されている削除ステートメントを考えると、テーブル "B"の列を変更してステートメント自体に触れずに、テーブル "A"から行を誤って削除する可能性があります。 [OK]をクリックすると、複数のテーブルを使用するたびにエイリアスを使用するようになります; – evilive

+1

@evilive相関サブクエリのためにそのように動作します。 'select * from table1 t1 whereは存在します(table2からのヌルを選択しますt2、t1.col1 = t2.col1);'。私。外部クエリのスコープは、その内部のサブクエリの最上位レベルまで拡張されます。したがって、問合せでどの列が使用されているかが明示的に示されている場合、Oracleは列がどの表から来るかを推測する必要があります。エイリアスの使用をサポートする別のケースを見つけるための小道具! – Boneist

+2

@evilive:これは実際にはOracle固有のものではありません。これは名前解決がSQL標準で動作するように定義されています –

4

'broken'クエリがサブクエリとして使用されても、外部クエリのテーブルの列を参照することができます。それは相関関係が働くために必要です。 test_valuesテーブルからtst_id2列を取得しています。両方の表に同じ列がある場合は、内側の表が優先されますが、ここでは該当しません。

From the documentation

Oracleは、サブクエリで、その後、親の文で名付けられたテーブルで指定されたテーブルを調べて、サブクエリで修飾されていない列を解決します。

テーブルエイリアスを追加すると、何が起きているのかを確認できます。このそれでもエラー:

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 

しかし、これは動作します:

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

それは明示的に(tv別名を経由して)test_valuesカラムを用いています。元のクエリは同じことを行っていましたが、暗黙的に行っていました。

+0

ありがとう、Boneistは少し速かった – evilive

+3

@evilive - 初めてではなく、おそらく最後の時間ではないでしょう...とにかくこれをここに残しておきます*少し違います* doclink * 8-) –

+1

@AlexPoole hurray for doc links! * {;-D(p.s. Happy New Year!) – Boneist

関連する問題