Convert Oracle legacy outer join to Ansi SQL

大憨熊 提交于 2019-12-02 00:02:20

Your query is equivalent to the below ANSI compliant query:

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;         

You have to place predicates b.empno = 190 and c.empno = 190 inside the ON clauses of the LEFT JOIN operations, otherwise LEFT JOIN becomes an INNER JOIN.

(N.B. This isn't an answer, as it looks like Giorgos's answer is what you were really after, but it's too long to go in a comment. I wanted to make sure you understood why your original query isn't doing what (I think) you think it is)

Your original query actually ends up doing an inner join, because you're asking for specific values for the b.empno and c.empno columns without including them in the left outer join. I.e. you're saying "first, left outer join b to a, and then afterwards, filter out any rows which don't have a b.empno = 190". That will get rid of any rows where b.empno is null as well as other b.empno values.

Here's a simple example showing the different behaviours:

Old-style left outer join with non-left outer join filter:

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

Old-style inner join with filter:

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

You can see that the results of the above two queries are identical, which means the first query with the left outer joins is really doing an inner join. And the ANSI join syntax equivalent query to this would be:

ANSI-style inner join with filter:

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

You can see the difference to the results by including the filtered column in the outer join in the original old-style query:

Old-style left outer join with left outer join filter

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 

And, as per Giorgos's answer, the equivalent ANSI join syntax query would be:

ANSI-style outer join with outer join filter:

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 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!