8

Here is a question which has been boggling me for few days now, and I searched and searched but couldn't find any convincing answer !

Simple question, why is it restricted to have 2 Outer Joins in SQL, on same table even with different columns being used, check the queries below for better understanding. Also I can overcome them using nested sub query or ANSI joins, but then why it is even restricted in the first place using (+) operator!

In this question I'm referring to the error :

ORA-01417: a table may be outer joined to at most one other table

What I want to ask is why this is allowed :

select * from
a, b, c
where a.a1 = b.b1
and a.a2 = c.c1

And why this is not allowed:

select * from
a, b, c
where a.a1(+) = b.b1
and a.a2(+) = c.c1

Please leave ANSI and Nested SubQueries alone

4

2 回答 2

10

Oracle 文档中描述了该限制:外部连接

Oracle 建议您使用 FROM 子句 OUTER JOIN 语法而不是 Oracle 连接运算符。使用 Oracle 连接运算符 (+) 的外连接查询受以下规则和限制的约束,这些规则和限制不适用于 FROM 子句 OUTER JOIN 语法:

...

在执行多于两对表的外连接的查询中,单个表可以是仅为另一个表生成的空表。因此,在 A 和 B 的连接条件以及 B 和 C 的连接条件中,不能将 (+) 运算符应用于 B 的列。有关外连接的语法,请参阅 SELECT。

这基本上意味着(在 ANSI/ISO 语法中描述)您不能使用旧(+)语法在 ANSI/ISO 中完全有效:

--- Query 1 ---
  a 
RIGHT JOIN b
  ON a.x = b.x
RIGHT JOIN c 
  ON a.y = c.y

或者:

--- Query 1b ---
  c 
LEFT JOIN 
    b LEFT JOIN a
        ON a.x = b.x 
  ON a.y = c.y

这只是旧 Oracle 语法的众多限制之一。


至于这种限制的原因,可能是实现细节或/和这种连接的模糊性。虽然上面的两个连接是 100% 等价的,但以下不等价于上面的两个:

--- Query 2 ---
  a 
RIGHT JOIN c 
  ON a.y = c.y 
RIGHT JOIN b
  ON a.x = b.x 

请参阅SQL-Fiddle中的测试所以问题来了。应该如何将专有连接解释为查询 1 或 2?

FROM a, b, c 
WHERE a.y (+) = c.y 
  AND a.x (+) = b.x 

如果表出现在(2 个或更多)外部联接的左侧,则没有限制。即使使用旧语法,这些也是完全有效的:

FROM a
  LEFT JOIN b ON a.x = b.x 
  LEFT JOIN c ON a.y = c.y
  ...
  LEFT JOIN z ON a.q = z.q

FROM a, b, ..., z
WHERE a.x = b.x (+) 
  AND a.y = c.y (+)
  ...
  AND a.q = z.q (+)
于 2013-06-16T17:35:56.857 回答
1

我强烈建议使用显式OUTER JOIN语法。从 Oracle 12c 开始,这个限制被放宽了1.4.3 增强的 Oracle Native LEFT OUTER JOIN 语法

在 Oracle 数据库的先前版本中,在执行多于两对表的外连接的查询中,单个表可能是仅为另一个表生成的空表。从 Oracle Database 12c 开始,一个表可以是多个表的空生成表。

代码:

CREATE TABLE a AS
SELECT 1 AS a1, 2 AS a2 FROM dual;

CREATE TABLE b AS
SELECT 1 AS b1 FROM dual;

CREATE TABLE c AS
SELECT 3 AS c1 FROM dual;

-- Oracle 12c: code below will work
SELECT * 
FROM a, b, c
WHERE a.a1(+) = b.b1
  AND a.a2(+) = c.c1;

输出:

A1  A2  B1  C1
-   -   1   3

db<>fiddle 演示 - Oracle 11g 将返回错误

db<>fiddle demo Oracle 12c/18c 将返回结果集

于 2018-09-23T10:25:47.737 回答