在 Oracle 查询中将连接从 Where 子句移动到 From 子句

Posted

技术标签:

【中文标题】在 Oracle 查询中将连接从 Where 子句移动到 From 子句【英文标题】:Move joins from Where clause to From clause in an Oracle query 【发布时间】:2020-11-05 03:14:20 【问题描述】:

我有以下 Oracle 查询,我想将连接从 Where 子句移动到 From 子句

select 
    * 
from
    A, B, C
where
    A.a (+)= B.a
    AND A.b (+) = B.b
    AND A.b = C.b;

所以我想出了以下查询

select
    *
from
    C,
    B left join A on (B.a = A.a and B.b = A.b and C.b = A.b);

我想知道这两个查询在语义上是否相同,是否会输出相同的结果

*** 编辑:尝试 2

select
    *
from    
    B left join A on (B.a = A.a and B.b = A.b)
    inner join C on C.b = A.b;

【问题讨论】:

不要混合现代显式 JOIN 和旧的逗号分隔的。到处切换到显式 JOIN。 那个查询实际上是无效的,因为应该在找到逗号分隔的 C 之前评估 ON 子句。 @jarlh 我刚刚编辑了我的问题。也许第二次尝试等同于原始查询? Attempt 2 相当于你的第一个查询 我同意尝试 2 等同于您的第一个查询。这是从旧语法到新语法的正确转换。因此,这两个查询甚至在您实际上是在内部联接表 A 时,都使您看起来像是在外部联接表 A 的方面。 (对于相同的列顺序,它必须是 select a.*, b.*, c.* ... 而不是 select *,但这是一个小细节。) 【参考方案1】:

在旧的 Oracle 连接语法中,(+) 将应用于外连接表的所有列。因此,在您的原始查询中,表 A 与表 B 外连接,因为

FROM a, b
WHERE a.a (+) = b.a AND a.b (+) = b.b

FROM b
LEFT join a ON a.a = b.a AND a.b = b.b

但是AND a.b = c.b 在您的查询中呈现这仅仅是一个内部联接,因为它必须是AND a.b (+) = c.b 才能工作的外部联接(在这种情况下,您可能也需要a.b = c.b,以免交叉连接两个表)。

所以您的查询归结为:

select * 
from a
inner join b on b.a = a.a and b.b = a.b
inner join c on c.b = a.b;

【讨论】:

【参考方案2】:

如果以下是您的工作查询,那么我必须说它没有达到预期的效果。

select 
    * 
from
    A, B, C
where
    A.a (+)= B.a -- b left join a
    AND A.b (+) = B.b -- b left join a
    AND A.b = C.b; -- c inner join a

这不过是所有三个表的内连接,因为最后一个条件使它成为 a 和 c 之间的内连接。仅当 a 和 c(以及 b)中都有可用数据时,它才会返回数据。 (内连接)

要获得准确的结果,您只需要一个内连接。

SELECT * FROM
B INNER JOIN A ON A.A=B.A AND A.B = B.B
INNER JOIN C ON A.B = C.B

【讨论】:

【参考方案3】:

您可能希望此查询为:

select * 
from B left join
     A
     using (a, b) left join
     C
     using (b)

【讨论】:

以上是关于在 Oracle 查询中将连接从 Where 子句移动到 From 子句的主要内容,如果未能解决你的问题,请参考以下文章

Oracle 查询性能优化(转)

如何强制 where 子句中的函数在 oracle 中执行一次?

Oracle:where 子句日期查询的问题

如何使用带有过滤器 where 子句的 oracle 外连接

oracle 性能优化建议

在 where 子句中执行 Oracle 查询