将Oracle旧外连接转换为Ansi SQL

时间:2016-11-24 09:49:00

标签: oracle 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;

提前致谢

2 个答案:

答案 0 :(得分:3)

(NB这不是一个答案,因为看起来Giorgos的答案就是你真正追求的,但是评论时间太长了。我想确保你理解为什么你的原始查询没有做什么(我认为)你认为它是什么)

您的原始查询实际上最终会执行内部联接,因为您要求b.empno和c.empno列的特定值,而不将它们包含在左外部联接中。即你说的是“首先,左外连接b到a,然后过滤掉没有b.empno = 190的任何行”。这将消除b.empno为null的任何行以及其他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 

答案 1 :(得分:2)

您的查询等同于以下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置于ON操作的LEFT JOIN子句中,否则LEFT JOIN将成为INNER JOIN