将涉及多个表的左外连接从 Informix 重写为 Oracle

Posted

技术标签:

【中文标题】将涉及多个表的左外连接从 Informix 重写为 Oracle【英文标题】:Rewrite left outer join involving multiple tables from Informix to Oracle 【发布时间】:2011-11-03 04:01:49 【问题描述】:

如何编写一个与以下 Informix 查询等效的 Oracle 查询?

select tab1.a,tab2.b,tab3.c,tab4.d 
  from table1 tab1,
       table2 tab2 OUTER (table3 tab3,table4 tab4,table5 tab5) 
 where tab3.xya = tab4.xya 
   AND tab4.ss = tab1.ss 
   AND tab3.dd = tab5.dd 
   AND tab1.fg = tab2.fg 
   AND tab4.kk = tab5.kk 
   AND tab3.desc = "XYZ"

我试过了:

select tab1.a,tab2.b,tab3.c,tab4.d 
  from table1 tab1,
       table2 tab2 LEFT OUTER JOIN (table3 tab3,table4 tab4,table5 tab5) 
 where tab3.xya = tab4.xya 
   AND tab4.ss = tab1.ss 
   AND tab3.dd = tab5.dd 
   AND tab1.fg = tab2.fg 
   AND tab4.kk = tab5.kk 
   AND tab3.desc = "XYZ"

正确的语法是什么?

【问题讨论】:

Oracle 的哪个版本?对于 8i 或更早版本,答案会有所不同。 Oracle 8i 已经有 100 年历史了。但是,它不支持连接吗? @GolezTroi - ANSI 样式的外连接仅在 Oracle 9i 或更高版本中受支持。在此之前,Oracle 只有自己的定制语法。 【参考方案1】:

每个连接写一个表,像这样:

select tab1.a,tab2.b,tab3.c,tab4.d 
from 
  table1 tab1
  inner join table2 tab2 on tab2.fg = tab1.fg
  left join table3 tab3 on tab3.xxx = tab1.xxx and tab3.desc = "XYZ"
  left join table4 tab4 on tab4.xya = tab3.xya and tab4.ss = tab3.ss
  left join table5 tab5 on tab5.dd = tab3.dd and tab5.kk = tab4.kk

请注意,虽然我的查询包含实际的左连接,但您的查询显然没有。 由于条件在哪里,您的查询应该表现得像内部连接。 (虽然我承认我不了解 Informix,所以也许我错了)。

The specfific Informix extension used in the question works a bit differently 关于左连接。除了联接本身的确切语法之外,这主要是因为在 Informix 中,您可以指定外部联接表的列表。这些将被左外连接,连接条件可以放在 where 子句中。请注意,这是对 SQL 的特定扩展。 Informix 还支持“普通”左连接,但您似乎不能将两者结合在一个查询中。

在 Oracle 中不存在此扩展,并且您不能将外连接条件放在 where 子句中,因为无论如何都会执行条件。

那么看看当你将条件移到 where 子句时会发生什么:

select tab1.a,tab2.b,tab3.c,tab4.d 
from 
  table1 tab1
  inner join table2 tab2 on tab2.fg = tab1.fg
  left join table3 tab3 on tab3.xxx = tab1.xxx
  left join table4 tab4 on tab4.xya = tab3.xya
  left join table5 tab5 on tab5.dd = tab3.dd and tab5.kk = tab4.kk
where
  tab3.desc = "XYZ" and
  tab4.ss = tab3.ss

现在,只会返回满足这两个条件的行。当没有找到行时它们不能为真,因此如果 table3 和/或 table4 中没有匹配的行,或者如果ss 在两者中的任何一个中为空,则这些条件之一将返回 false,并且没有行被退回。这有效地将您的外部联接更改为内部联接,因此显着改变了行为。

PS:left joinleft outer join 是一样的。这意味着您可以选择将第二个表连接到第一个表(左侧)。如果连接的“左”部分中只有数据,则返回行。在 Oracle 中,您还可以right [outer] join 使不是左表而是右表成为前导表。如果任一表中有数据,甚至full [outer] join 都会返回一行。

【讨论】:

谢谢。您的回答让我知道了如何解决我的实际问题 OUTER(...) 子句将连接变为左外连接。 (该 Informix 语法不支持任何其他类型的外连接。Informix 的更高版本,如 Oracle 的更高版本,支持 ANSI 连接。) Oracle 确实支持 LEFT、RIGHT 和 FULL OUTER JOIN。没有 LEFT INNER JOIN 或 LEFT CROSS JOIN 这样的东西。因此 LEFT JOIN 只是 LEFT OUTER JOIN 的缩写。 'OUTER' 关键字是可选的,而 LEFT、RIGHT 和 FULL 关键字是必需的。 你的第一个左连接可以是内部的,因为 where 消除了任何空扩展行。但是由于您只是在猜测条件和连接顺序,因此您最好将 where 测试移至左连接。 @philipxy 好点,即使答案是 8 年 ;-) 所以,为时已晚 8 年,我决定查找(并链接)这个 Informix 语法,结果证明外部连接条件确实应该在 Informix 的 where 子句中。所以我现在已经将条件移动到连接,以匹配所要求的内容。我还添加了第二个 sn-p 来更好地解释数据库之间的差异,因为在 Oracle 中,您确实不应该将左连接条件放在 where 子句中。感谢您的推动!【参考方案2】:

我猜你想要类似的东西

SELECT tab1.a, tab2.b, tab3.c, tab4.d
  FROM table1 tab1 
       JOIN table2 tab2 ON (tab1.fg = tab2.fg)
       LEFT OUTER JOIN table4 tab4 ON (tab1.ss = tab4.ss)
       LEFT OUTER JOIN table3 tab3 ON (tab4.xya = tab3.xya and tab3.desc = 'XYZ')
       LEFT OUTER JOIN table5 tab5 on (tab4.kk = tab5.kk AND
                                       tab3.dd = tab5.dd)

【讨论】:

以上是关于将涉及多个表的左外连接从 Informix 重写为 Oracle的主要内容,如果未能解决你的问题,请参考以下文章

LINQ:具有多个条件的左外连接

将两个查询的左外连接转换为 LINQ

使用 LINQ 查询语法 EF Core C# 的左外连接

如何在 obiee 的左外连接的一部分中包含分析过滤器(左连接变为内连接)

左外连接和右外连接的区别

带条件sql的左外连接