子 select 损坏的查询应该会导致错误,但 returns 行

Query with broken sub-select should result in error but returns rows

我不明白这种情况下的行为。在我的理解中,带有无效子查询的查询应该会导致错误。但在这个例子中它 returns 一些行。

测试数据:

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"-table 而不是 "test_lookup"-[= 中获取 "test_id2"-列27=] 如子查询中所述,但不对内部和外部部分使用别名。

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         
*/

原因是因为当子查询中不存在但在外部查询中存在的非别名列时,Oracle 假定您引用的是外部查询中的列。

使用别名,您感到困惑的查询如下所示:

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

希望这能让事情变得更清楚?

您看到的问题是一个很好的例子,说明了为什么您应该始终标记 table 它们来自的列 - 这样一开始就更容易维护查询!

当您的 'broken' 查询用作子查询时,它仍然可以引用外部查询的 table 列;这是关联工作所必需的。它从 test_values table 中选取 tst_id2 列。如果两个 table 有相同的列,那么内部的 table 将优先,但这里不是这种情况。

From the documentation:

Oracle resolves unqualified columns in the subquery by looking in the tables named in the subquery and then in the tables named in the parent statement.

您可以通过添加 table 别名来查看发生了什么;这仍然是错误:

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' );

它明确地使用了 test_values 列(通过 tv 别名);您的原始查询也在做同样的事情,但是是隐含的。