子 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 将优先,但这里不是这种情况。
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
别名);您的原始查询也在做同样的事情,但是是隐含的。
我不明白这种情况下的行为。在我的理解中,带有无效子查询的查询应该会导致错误。但在这个例子中它 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 将优先,但这里不是这种情况。
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
别名);您的原始查询也在做同样的事情,但是是隐含的。