同桌上有2个外接头?

时间:2013-06-14 20:53:40

标签: sql oracle join

这是一个令我难以置信几天的问题,我搜索并搜索但找不到任何令人信服的答案!

简单的问题,为什么限制在SQL中有2个外部联接,即使使用不同的列也在同一个表上,检查下面的查询以便更好地理解。我也可以使用嵌套的子查询或ANSI连接来克服它们,但是为什么它首先使用(+)运算符进行限制!

在这个问题中,我指的是错误:

  

ORA-01417:一张桌子最多可以与另外一张桌子连在一起

我想问的是为什么允许这样做:

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

为什么不允许这样做:

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

请单独留下ANSI和嵌套子查询

2 个答案:

答案 0 :(得分:10)

Oracle文档中描述了该限制:Outer Joins

  

Oracle建议您使用FROM子句OUTER JOIN语法而不是Oracle join运算符。使用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 (+)

答案 1 :(得分:1)

我强烈建议使用显式OUTER JOIN语法。从Oracle 12c开始,此限制已放松1.4.3 Enhanced Oracle Native LEFT OUTER JOIN Syntax

  

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

代码:

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 demo - Oracle 11g will return error

db<>fiddle demo Oracle 12c/18c will return resultset