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_b有name列。既然没有,那就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 语句中避免内部捕获段落中的建议:
使用适当的表别名限定语句中的每个列引用。
因为
当嵌套子查询引用表中的列时,Oracle 执行相关子查询,该列引用子查询上一级的父语句。 http://docs.oracle.com/cd/E11882_01/server.112/e41084/queries007.htm#SQLRF52357
这意味着为了确定子查询是否相关,Oracle 也必须尝试解析子查询中的名称,包括外部语句上下文。对于无前缀,name这是唯一可能的解决方案。
| 归档时间: |
|
| 查看次数: |
5443 次 |
| 最近记录: |