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

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

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


据我了解,Oracle将其视为

select * from table_a where name = name;


但是我不明白为什么?

#1 楼

即使table_b没有name列,该查询在语法上也是正确的SQL。原因是范围解析。

解析查询时,首先检查table_b是否具有name列。既然没有,则检查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 ;


or:

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
19年2月16日在14:54



#2 楼

因为


当嵌套的子查询
引用表中的列时,Oracle执行相关子查询,该表引用了子查询上一级父语句。
> http://docs.oracle.com/cd/E11882_01/server.112/e41084/queries007.htm#SQLRF52357


这意味着为了确定子查询是否相关,Oracle必须尝试在子查询(包括外部语句上下文)中解析名称。对于非前缀的name,这是唯一可能的分辨率。

#3 楼

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

评论


“ table_b中没有名称字段,因此Oracle从table_a中获取一个。”正确。 “我认为这将产生某种笛卡尔积。”错误。该查询来自table_a,其中...。它将返回来自table_a的所有行,但名称为null的行除外。

–超立方体ᵀᴹ
16-6-27在9:04



表访问完全是Oracle告诉您它正在进行顺序扫描的方式。

– Joishi Bodio
16年6月27日在15:51

您的PLAN无关紧要-可能有巨大的表建立索引-我假设您正在运行测试数据?

–Vérace
16年6月27日在18:02