将 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 = 190
和 c.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
我有一个复杂的非 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 = 190
和 c.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