SQL从Oracle转换为ANSI JOIN

wj8zmpe1  于 2023-02-11  发布在  Oracle
关注(0)|答案(4)|浏览(195)

如何从旧的Oracle连接类型转换为ANSI连接,为什么?

SELECT *
FROM a, b, c
WHERE b.id (+) = a.id1
AND b.xxx = c.yyy
AND c.id (+) = a.id2

--应该是这个1?

select * from
A
left outer join B on B.ID = A.ID1
left outer join C on C.ID = A.ID2 AND B.xxx = C.yyy

--或者这两个?

select * from
A
left outer join C on C.ID = A.ID2
left outer join B on B.ID = A.ID1 AND B.xxx = C.yyy
30byixjq

30byixjq1#

您还可以使用Oracle SQL Developer进行“作弊”。
粘贴ANSI SQL查询或Oracle SQL查询,选择它,右键单击,然后使用转换功能。
SQL解析器将为您重写JOINS。
因此,这适用于任何查询,而不仅仅是您的问题/场景中的查询。
当然,您应该检查查询返回的执行计划和数据,以确保它们在功能上是等效的。

xcitsw88

xcitsw882#

根据Oracle documentation
如果WHERE子句包含将表B中的列与常数进行比较的条件,则必须对该列应用(+)运算符,以便Oracle返回表A中已为该列生成空值的行。否则,Oracle仅返回简单联接的结果。
因此,bc之间存在一个内连接。由于整体条件,这将把所有连接都转换为INNER JOINbc中需要有有效值才能使该条件生效。
我认为相应的逻辑是:

SELECT *
FROM a JOIN
     b
     ON b.id = a.id1 JOIN
     c
     ON c.id = a.id2 AND b.xxx = c.yyyy;

也就是说,简单的相等消除将外联接转换为内联接。
当然,你可以测试这个。

oknwwptz

oknwwptz3#

两个选项都没有:

select *
from   A
       left outer join B on B.ID = A.ID1
       left outer join C on C.ID = A.ID2 AND B.xxx = C.yyy

将写成:

SELECT *
FROM a, b, c
WHERE b.id (+) = a.id1
AND   b.xxx = c.yyy (+)
AND   c.id (+) = a.id2

以及:

select *
from   A
       left outer join C on C.ID = A.ID2
       left outer join B on B.ID = A.ID1 AND B.xxx = C.yyy

将写成:

SELECT *
FROM a, b, c
WHERE b.id (+) = a.id1
AND   b.xxx (+) = c.yyy
AND   c.id (+) = a.id2

你所拥有的是:

SELECT *
FROM   a
       INNER JOIN b ON (a.id1 = b.id)
       INNER JOIN c ON (a.id2 = c.id AND b.xxx = c.yyy)

为甚么?

SELECT *
FROM   a, b, c
WHERE  b.id (+) = a.id1
AND    b.xxx = c.yyy
AND    c.id (+) = a.id2

该行:

AND    b.xxx = c.yyy

要求有一个b和一个c行;当存在左外连接时,这将不会发生,因此该连接等同于内连接,并且查询可被重写为:

SELECT *
FROM   a, b, c
WHERE  b.id = a.id1
AND    b.xxx = c.yyy
AND    c.id = a.id2

这样就很清楚所有的联接都是内联接。
你可能想写的是:

select *
from   A,
       (
         SELECT b.id AS b_id,
                c.id AS c_id,
                b.xxx,
                c.yyy
         FROM   b, c
         WHERE  b.xxx = c.yyy
       ) bc
WHERE  bc.b_id (+) = a.id1
AND    bc.c_id (+) = a.id2

即:

select *
from   A
       left outer join (
         SELECT b.id AS b_id,
                c.id AS c_id,
                b.xxx,
                c.yyy
         FROM   b
                INNER JOIN c ON b.xxx = c.yyy
       ) bc
       on bc.b_id = a.id1 AND bc.c_id = a.id2

或者,在联接中使用括号设置联接的优先级:

SELECT *
FROM   a
       LEFT OUTER JOIN (
         b
         INNER JOIN c
         ON b.xxx = c.yyy
       )
       ON b.id = a.id1 AND c.id = a.id2
  • db〈〉小提琴here *
pu3pd22g

pu3pd22g4#

如果运行simple explain plan并检查结果,您可能会看到它生成了两个inner join
一个一个

  • db〈〉小提琴here *

相关问题