如何在 >2 个表上进行外部联接 (Oracle)

Posted

技术标签:

【中文标题】如何在 >2 个表上进行外部联接 (Oracle)【英文标题】:How to do Outer Join on >2 Tables (Oracle) 【发布时间】:2011-04-12 21:46:42 【问题描述】:

我不确定如何描述我的表结构,所以希望这是有道理的...

我有 3 个层次关系表,因此 A 与 B 具有一对多关系,而 B 又与 C 具有一对多关系。诀窍是 B 和 C 中的外键允许为空(即没有定义父级)。我也有 D 和 E,与 A、B 或 C 无关(直接)。

最后,我有 F,它是一个与 C、D 和 E 具有多对一关系的连接表。它的所有字段(其他表的 FK)都不能为空。

我想编写一个 SQL 语句,将所有表连接到一个结果集中。我知道我必须使用外部联接,因为我希望返回所有 A,无论它在 B 中是否有子节点,并且与 B 和 C 类似。

问题一:我一直在看ANSI外连接语法(我之前只用过Oracle“(+)”),找不到外连接超过2个表的例子。有人可以提供/指出一个例子吗?

问题二: 是否可以根据连接表 F 包含表 D 和 E 中的记录?如果是这样,这是通过外部连接完成的吗?

谢谢!

编辑

当然,就在我发布这个之后,我找到了一个回答问题 1 的示例。但是,问题 2 仍然让我难过。

例子:

         SELECT A.a,
                B.b,
                C.c
           FROM A
FULL OUTER JOIN B ON B.a = A.a
FULL OUTER JOIN C ON C.b = B.b

【问题讨论】:

你可能不想要 FULL OUTER JOIN;它存在,但很少使用(或有用)。 您没有指定 F 中的哪些列与其他每个表连接 - 这意味着没有人可以给出明确的答案。 能否请您发布一些示例数据和您想要获取的记录集? A、B 和 C 的名称信息量不大。 @Jonathan,据我了解 ANSI 联接(我承认我只是在学习)我需要使用完全联接,因为我想要表 A 中的所有记录,即使其中没​​有子记录表 B 和表 B 中的所有记录,即使没有定义表 A 的外键。左连接或右连接只会给我一个关系方向的空值。表 F 只有 3 个字段,它们是表 C、D 和 E 的外键。Bill 在“绘制”模式的回答中做得很好。 【参考方案1】:

所以我将您的架构可视化如下:

A --o< B --o< C --< F >-- D
                      >-- E

你当然可以做多个连接,你也可以用括号对连接表达式进行分组,就像你可以对算术表达式进行分组一样。

SELECT ...
FROM A LEFT OUTER JOIN (
  B LEFT OUTER JOIN (
    C LEFT OUTER JOIN (
      F INNER JOIN D ON D.d = F.d
        INNER JOIN E ON E.e = F.e
      ) ON C.c = F.c
    ) ON B.b = C.b
) ON A.a = B.a

这些括号不是子查询,它们只是对连接操作进行分组。

【讨论】:

这是“绘制”我的架构的好方法。谢谢!我需要花一些时间弄清楚您的 select 语句是否符合我的期望,但我确实认为我需要根据上面对 Jonathan 的评论使用 FULL 连接。【参考方案2】:

为了清楚起见,大写字母指代表,小写字母指代主键/外键列。我可能应该把它写成类似于 Quassnoi,但会一直这样,因为它就是这样开始的。

此 SQL 返回我正在寻找的结果:

         SELECT A.a,
                B.b,
                C.c,
                D.d,
                E.e
           FROM A
FULL OUTER JOIN B ON B.a = A.a
FULL OUTER JOIN C ON C.b = B.b
FULL OUTER JOIN F ON F.c = C.c
FULL OUTER JOIN D ON D.d = F.d
FULL OUTER JOIN E ON E.e = F.e

我尝试像 Bill 一样设置我的 SQL,但使用 FULL 连接而不是 LEFT 连接,但它没有返回与我相同的结果。我不能说我完全理解他的 SQL,但是 INNER 连接过滤了一些结果。

【讨论】:

【参考方案3】:
 select a.*, b.*, c.*
 from a
 left outer join b on a.b_id = b.id
 left outer join c on a.c_id = c.id

现在,在其中获取 D、E 和 F 变得更加棘手:

select c.*, d.*, e.*
from C
inner join f on c.id = f.c_id
inner join d on d.id = f.d_id
inner join e on d.id = f.e_id

然后我们把它们放在一起:

 select a.*, b.*, cde.*
 from a
 left outer join b on a.b_id = b.id
 left outer join 
 (select c.id as c_id, c.*, d.*, e.*
   from C
   inner join f on c.id = f.c_id
   inner join d on d.id = f.d_id
   inner join e on d.id = f.e_id) CDE
 on a.c_id = cde.c_id

【讨论】:

谢谢!我们一定是同时发帖的。【参考方案4】:
SELECT  a.*, b.*, c.*, d.*, e.*
FROM    a
LEFT JOIN
        b
ON      b.a = a.id
LEFT JOIN
        с
ON      c.b = b.id
LEFT JOIN
        f
ON      f.с = c.id
LEFT JOIN
        d
ON      d.id = f.d
LEFT JOIN
        e
ON      e.id = f.e

【讨论】:

以上是关于如何在 >2 个表上进行外部联接 (Oracle)的主要内容,如果未能解决你的问题,请参考以下文章

同一请求中的多个外部联接

如何计算联接表上的行数

外部联接中的内部联接导致性能不足,有啥不同的方法?

详解T-SQL的联接机制

BigQuery联接基于(Array CONTAINED IN Array)条件的2个表

PHP 处理时间