将 Oracle 遗留外部联接转换为 Ansi SQL

Convert Oracle legacy outer join to Ansi SQL

我有一个复杂的非 ANSI 查询,我需要在 ANSI 查询中进行转换。

所以我举个小例子来说明我的问题

输入查询

 SELECT a.name,
         a.empno,
         b.loc,
         c.inr
    FROM a,
         b,
         c
   WHERE a.deptno = b.deptno(+)
     AND b.empno(+) = 190
     a.deptno = c.deptno(+)
     AND c.empno(+) = 190;

提前致谢

您的查询等同于以下符合 ANSI 标准的查询:

SELECT a.name,
       a.empno,
       b.loc,
       c.inr
FROM tab a
LEFT JOIN tab b ON a.deptno = b.deptno AND b.empno = 190
LEFT JOIN tab c ON a.deptno = c.deptno AND c.empno = 190;         

您必须将谓词 b.empno = 190c.empno = 190 放在 LEFT JOIN 操作的 ON 子句中,否则 LEFT JOIN 变成 INNER JOIN.

(N.B。这不是答案,因为看起来 Giorgos 的答案是你真正想要的,但评论太长了。我想确保你明白为什么你原来的查询没有做你认为的(我认为))

您的原始查询实际上最终执行了内部联接,因为您要求 b.empno 和 c.empno 列的特定值而不将它们包含在左外部联接中。 IE。你是说 "first, left outer join b to a, and then afterwards, filter out any rows which don't have a b.empno = 190"。这将删除 b.empno 为空的任何行以及其他 b.empno 值。

这是一个显示不同行为的简单示例:

带有非左外连接过滤器的旧式左外连接:

WITH t1 AS (SELECT 1 ID, 10 val FROM dual UNION ALL
            SELECT 2 ID, 20 val FROM dual UNION ALL
            SELECT 3 ID, 30 val FROM dual),
     t2 AS (SELECT 1 ID, 100 val FROM dual UNION ALL
            SELECT 1 ID, 150 val FROM dual UNION ALL
            SELECT 2 ID, 200 val FROM dual UNION ALL
            SELECT 2 ID, 250 val FROM dual)
SELECT t1.id, t1.val, t2.val
FROM   t1,
       t2
WHERE  t1.id = t2.id(+)
AND    t2.val = 200
ORDER BY t1.id, t2.val;

        ID        VAL        VAL
---------- ---------- ----------
         2         20        200

带过滤器的旧式内部联接:

WITH t1 AS (SELECT 1 ID, 10 val FROM dual UNION ALL
            SELECT 2 ID, 20 val FROM dual UNION ALL
            SELECT 3 ID, 30 val FROM dual),
     t2 AS (SELECT 1 ID, 100 val FROM dual UNION ALL
            SELECT 1 ID, 150 val FROM dual UNION ALL
            SELECT 2 ID, 200 val FROM dual UNION ALL
            SELECT 2 ID, 250 val FROM dual)
SELECT t1.id, t1.val, t2.val
FROM   t1,
       t2
WHERE  t1.id = t2.id
AND    t2.val = 200
ORDER BY t1.id, t2.val;

        ID        VAL        VAL
---------- ---------- ----------
         2         20        200

可以看到上面两个查询的结果是一样的,也就是说第一个左外连接的查询是真正的内连接。 ANSI 连接语法等效查询为:

带过滤器的 ANSI 样式内部联接:

WITH t1 AS (SELECT 1 ID, 10 val FROM dual UNION ALL
            SELECT 2 ID, 20 val FROM dual UNION ALL
            SELECT 3 ID, 30 val FROM dual),
     t2 AS (SELECT 1 ID, 100 val FROM dual UNION ALL
            SELECT 1 ID, 150 val FROM dual UNION ALL
            SELECT 2 ID, 200 val FROM dual UNION ALL
            SELECT 2 ID, 250 val FROM dual)
SELECT t1.id, t1.val, t2.val
FROM   t1
       INNER JOIN t2 ON t1.id = t2.id
WHERE  t2.val = 200;

        ID        VAL        VAL
---------- ---------- ----------
         2         20        200

您可以通过在原始旧式查询的外连接中包含过滤列来查看结果的差异:

带左外连接过滤器的旧式左外连接

WITH t1 AS (SELECT 1 ID, 10 val FROM dual UNION ALL
            SELECT 2 ID, 20 val FROM dual UNION ALL
            SELECT 3 ID, 30 val FROM dual),
     t2 AS (SELECT 1 ID, 100 val FROM dual UNION ALL
            SELECT 1 ID, 150 val FROM dual UNION ALL
            SELECT 2 ID, 200 val FROM dual UNION ALL
            SELECT 2 ID, 250 val FROM dual)
SELECT t1.id, t1.val, t2.val
FROM   t1,
       t2
WHERE  t1.id = t2.id(+)
AND    t2.val(+) = 200
ORDER BY t1.id, t2.val;

        ID        VAL        VAL
---------- ---------- ----------
         1         10 
         2         20        200
         3         30 

并且,根据 Giorgos 的回答,等效的 ANSI 连接语法查询将是:

带有外连接过滤器的 ANSI 样式外连接:

WITH t1 AS (SELECT 1 ID, 10 val FROM dual UNION ALL
            SELECT 2 ID, 20 val FROM dual UNION ALL
            SELECT 3 ID, 30 val FROM dual),
     t2 AS (SELECT 1 ID, 100 val FROM dual UNION ALL
            SELECT 1 ID, 150 val FROM dual UNION ALL
            SELECT 2 ID, 200 val FROM dual UNION ALL
            SELECT 2 ID, 250 val FROM dual)
SELECT t1.id, t1.val, t2.val
FROM   t1
       left OUTER JOIN t2 ON t1.id = t2.id AND t2.val = 200
ORDER BY t1.id, t2.val;

        ID        VAL        VAL
---------- ---------- ----------
         1         10 
         2         20        200
         3         30