为什么这个查询有效?

eag*_*ose 36 oracle subquery select

我有两个表,table_a (id, name) 和 table_b (id),假设在 Oracle 12c 上。

为什么这个查询不返回异常?

select * from table_a where name in (select name from table_b);
Run Code Online (Sandbox Code Playgroud)

据我了解,Oracle 认为这是

select * from table_a where name = name;
Run Code Online (Sandbox Code Playgroud)

但我不明白的是为什么?

ype*_*eᵀᴹ 60

即使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
                );
Run Code Online (Sandbox Code Playgroud)

至于查询将给出的结果,对于 的每一行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) ;
Run Code Online (Sandbox Code Playgroud)

或者:

select a.* 
from table_a  a
where a.name = a.name ;
Run Code Online (Sandbox Code Playgroud)

或者:

select a.* 
from table_a  a
where a.name is not null ;
Run Code Online (Sandbox Code Playgroud)

如果table_b为空,则查询将不返回任何行(感谢@ughai 指出这种可能性)。


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

select a.* from table_a where a.name in (select b.name from table_b); 
Run Code Online (Sandbox Code Playgroud)

你会马上得到错误。当表前缀被省略时,发生这种错误并不难,尤其是在更复杂的查询中,更重要的是,不被注意。

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

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


Ser*_*erg 8

因为

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

这意味着为了确定子查询是否相关,Oracle 也必须尝试解析子查询中的名称,包括外部语句上下文。对于无前缀,name这是唯一可能的解决方案。