添加 2 表条件时,Oracle 左外连接停止返回结果

Posted

技术标签:

【中文标题】添加 2 表条件时,Oracle 左外连接停止返回结果【英文标题】:Oracle left outer join stops returning results when 2-table condition added 【发布时间】:2015-01-20 19:03:32 【问题描述】:

我有一个包含一整串内连接和左连接的 oracle sql 查询。但是,当我添加最后一个左连接条件时,它会停止返回结果。这最终可能是一个简单的答案,例如“您不能对来自 2 个表的列进行外部联接”,但我找不到任何适用于 oracle 的规则,并且有很多示例显示相反的情况。 sql查询为:

  FROM a, b,
       c, d,
       e, f,
       g, h,
       (SELECT id5 FROM
        some_table WHERE
           conditions) i,
       (SELECT id7, type FROM
        some_other_table WHERE
           conditions) j
  WHERE b.time in (range) AND
        b.count <> 0 AND
        b.id1 = e.id1 AND
        e.type = g.type AND
        g.type2 = f.type2 AND
        b.id2 = a.id2(+) AND
        b.time = a.time(+) AND
        b.id3 = c.id3(+) AND
        b.time = c.time(+) AND
        c.id4 = d.id4(+) AND
        c.time = d.time(+) AND
        c.id5 = i.id5(+) AND
        c.time = h.time(+) AND
        c.id6 = h.id6(+) AND
        h.id7 = j.id7(+); --AND
        --e.type = j.type(+);

当我取消注释最终条件时,不会返回任何结果。由于这应该是外部连接,因此不应该发生这种情况。那么,这里的某些东西一定使它不像外部连接?

这里的某个地方有错字或错误吗?有没有我违反的预言规则?有什么可以通过切换到 ANSI 连接格式来解决的吗?

谢谢

【问题讨论】:

可能没有与新查询匹配的结果? 我确定没有。但它是一个外部连接。所以这不应该影响返回的行数。澄清问题。 是的,好点。那么,删除线后你会得到什么样的结果?任何看起来都会导致问题的东西,特别是从 e 或 j 表中收集的行? Ansi 语法是个不错的尝试。结果如何? 另一个猜测:您将 j 外部连接到两个不同的表 h 和 e。这似乎是使最后一行如此独特的一件事。如果你离开最后一行并取出它上面的那一行,看看是否会发生同样的事情。否则,这个查询对我来说太复杂了。 【参考方案1】:

您在将查询转换为简单形式时遗漏了某些内容,或者我在操作中遗漏了某些内容,但看起来查询可能没有按照您认为的那样执行。以标准 ANSI 形式重写更能说明问题:

FROM a
right outer join b
  on  b.id2  = a.id2
  AND b.time = a.time
right outer join c
  on  c.id3  = b.id3
  AND c.time = b.time
left outer join d
  on  d.id4  = c.id4
  AND d.time = c.time
join e
  on  e.id1 = b.id1
cross join f
join g
  on  g.type  = e.type
  AND g.type2 = f.type2
left outer join h
  on  h.time = c.time
  AND h.id6  = c.id6
left outer join(
     SELECT id5 FROM
      some_table WHERE
         conditions) i
  on  i.id5 = c.id5
left outer join(
     SELECT id7, type FROM
      some_other_table WHERE
         conditions) j
  on  j.id7 = h.id7
  and j.type = e.type   --> the criteria in question
where b.time in (range)
  AND b.count <> 0;

你觉得这合适吗?您没有提到 RIGHT OUTER 连接,但我希望您忘记了。您确实提到了 INNER 连接,但表 f 根本没有连接标准,所以我使用了 CROSS 连接,也希望这也是您的意图。

表 e 的连接条件是否应该是这样的?根据您设置的模式,我希望在这里看到“id5”而不是“id1”。当然,您已经更改了所有名称以提交简化示例,因此这可能没有意义。因此,我建议的第一件事是,您可以像我一样使用真实的表名和列名将原始代码重写为 ANSI 格式。你可能会看到一些东西。

您是正确的,添加标记的条件应该不会影响结果集中的行数。既然如此,那就有别的事情发生了。

要找出是什么,请注释掉整个最后一个连接。如果您发现有问题,请继续注释表格以找到问题所在。如果一切看起来都不错,只执行形成“表”j 的嵌套查询。我想不出它可能包含的任何内容会导致您解释的情况,但无论如何都要检查一下。

最后,如果所有其他方法都失败了,则只使用表 e 和 j 形成查询,然后只使用表 h 和 j(以及它们相应的连接条件)。看看会发生什么。

然后回到这里,向我们解释问题是如何一直存在于其他地方的。 :)

【讨论】:

我知道这是一个老问题,读完后我想知道为什么我没有评论你的答案,所以你可以编辑它,我可以选择它是正确的......我列出的所有标准是正确的,但我删除了任何不参与连接的内容。我的最终查询基本上看起来像你的,除了我在 f 之前加入了 g,避免了交叉连接(不记得为什么我没有按字母顺序命名表)。无论如何,原始查询包含足够的条件来避免完全外连接,但 Oracle 的语法规则没有考虑到这一点; ANSI 格式使其明确且有效。 哦,我还更改了顺序,以便所有外连接都是左外连接(以 b 开头),并且 f 确实具有与 g 的连接标准(您包括但可能由于 f 而错过在 g) 之前按字母顺序排列。以 b 开头是有充分理由的,但没有充分理由不以不同的顺序命名此问题中的表,因此我的简化示例以 :p 开头【参考方案2】:

问题(如问题的 cmets 中所建议的)是 h.id7 = j.id7(+) AND e.type = j.type(+) 在功能上等同于 a.id1 = b.id1(+) and c.id2 = b.id2(+)。 oracle join 语法不够精确,看不出来,由于其他连接条件,这不是全外连接,所以是不允许的。

这应该导致错误,但查询中的其他内容抑制了错误,我不清楚这是怎么发生的。无论如何,切换到 ANSI 格式使我能够更精确地指定连接条件,并且查询按预期工作。

【讨论】:

以上是关于添加 2 表条件时,Oracle 左外连接停止返回结果的主要内容,如果未能解决你的问题,请参考以下文章

数据库连接

左外连接与右外连接区别?

oracle左连接查询和右连接查询随便举个例子谢谢!

5.6 进阶6:多表连接查询

Oracle 多表查询

[Oracle]多表连接技术-交叉连接非等值连接等值连接外连接