为什么此查询不返回异常?
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语句中避免内部捕获中的建议段落中进行说明:
用适当的表别名限定语句中的每个列引用。
#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
评论
您如何如此精确地剖析SQL引擎的内部工作原理?
– RinkyPinku
19年2月16日在14:54