为什么此查询有效?


37

我有两个表,table_a(标识,名称)和table_b(标识),在Oracle 12c中说。

为什么此查询不返回异常?

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

据我了解,Oracle认为这是

select * from table_a where name = name;

但是我不明白为什么呢?

Answers:


61

即使table_b没有name列,查询在语法上也是正确的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为空,查询将不返回任何行(thnx指向@ughai指出这种可能性)。


那(您没有得到错误的事实)可能是所有列引用都应以表名/别名作为前缀的最佳原因。如果查询是:

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

您将立即得到错误。当省略表前缀时,发生此类错误并不困难,尤其是在更复杂的查询中,甚至更重要的是,也不会引起注意。

另请参阅Oracle文档:静态SQL语句中名称解析,内部捕获中的示例B-6 和SELECT和DML语句中的避免内部捕获段落中的建议:

使用适当的表别名来限定语句中的每个列引用。


您如何如此精确地剖析SQL引擎的内部工作原理?
RinkyPinku


4

Oracle中没有name字段,table_b因此Oracle从中选择一个table_a。我尝试了,EXPLAIN PLAN但这只给了我一个TABLE ACCESS FULL。我认为这将在两个表之间生成某种笛卡尔积,从而导致table_a子查询返回所有名称的列表。


5
“ table_b中没有名称字段,因此Oracle从table_a中获取一个。” 正确。“我认为这将产生某种笛卡尔积。” 错误。该查询具有from table_a where ...。它将返回table_anamenull 以外的所有行。
ypercubeᵀᴹ

1
TABLE ACCESS FULL只是Oracle告诉您它正在进行顺序扫描的方式。
Joishi Bodio

1
您的PLAN无关紧要-可能有巨大的表编制索引-我假设您正在运行测试数据?
Vérace
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.