解释这个内部连接和自然连接之间的输出差异

Ksh*_*rma 3 oracle join

NATURAL JOIN 是一种 JOIN 操作,它根据要连接的两个表中的公共列为您创建隐式连接子句。NATURAL JOIN 可以是 INNER 连接、LEFT OUTER 连接或 RIGHT OUTER 连接。默认为内部联接。来源

因此,如果两个表都有一个公共列,自然连接可以是实现内部连接的一种简写方式。

考虑下表:

SELECT * FROM t1;
/*
        ID PLANET  
---------- --------
         1 jupiter 
         2 earth 
*/
Run Code Online (Sandbox Code Playgroud)

我们将表加入到自身中:

SELECT first.id, first.planet FROM t1 first INNER JOIN t1 second ON first.id=second.id;
/*
        ID PLANET  
---------- --------
         1 jupiter 
         2 earth   
*/
Run Code Online (Sandbox Code Playgroud)

尝试使用自然连接符号做同样的事情:

SELECT id, planet FROM t1 NATURAL JOIN t1;
/*
        ID PLANET  
---------- --------
         1 jupiter 
         1 jupiter 
         2 earth   
         2 earth   
*/
Run Code Online (Sandbox Code Playgroud)

鉴于这里的自然连接是使用内部连接实现的,为什么会有多行?

更新:

使用表别名运行相同的连接有不同的输出:

SELECT id, planet FROM t1 first NATURAL JOIN t1 second;
/*
        ID PLANET  
---------- --------
         1 jupiter 
         2 earth   
*/
Run Code Online (Sandbox Code Playgroud)

Bal*_*app 6

Oracle 数据库在内部不理解 ANSI 连接语法(除了FULL OUTER JOIN),它将此类查询重写为它自己的旧连接语法。如果启用优化器跟踪,例如:

alter session set events '10053 trace name context forever, level 1';
Run Code Online (Sandbox Code Playgroud)

并运行查询,在生成的跟踪文件中,您可以查看执行的查询的最终形式。

select id, planet from t1 ta natural join t1 tb
Run Code Online (Sandbox Code Playgroud)

转换为(BP 是我的架构):

Final query after transformations:******* UNPARSED QUERY IS *******
SELECT "TB"."ID" "ID","TB"."PLANET" "PLANET" FROM "BP"."T1" "TA","BP"."T1" "TB"
WHERE "TA"."PLANET"="TB"."PLANET" AND "TA"."ID"="TB"."ID"
Run Code Online (Sandbox Code Playgroud)

select id, planet from t1 natural join t1
Run Code Online (Sandbox Code Playgroud)

转化为:

Final query after transformations:******* UNPARSED QUERY IS *******
SELECT "T1"."ID" "ID","T1"."PLANET" "PLANET" FROM "BP"."T1" "T1","BP"."T1" "T1"
WHERE "T1"."PLANET"="T1"."PLANET" AND "T1"."ID"="T1"."ID"
Run Code Online (Sandbox Code Playgroud)

这就是问题所在,"T1"."PLANET"="T1"."PLANET" AND "T1"."ID"="T1"."ID"

但不要问我为什么,这只是 Oracle 中那些“无法解释”的事情之一。

我见过一个案例,其中转换导致类似的模棱两可的最终查询,并且跟踪文件中有实际的错误消息,但数据库仍然返回错误的结果并且没有错误给客户端。