何时或为啥要使用右外连接而不是左连接?

Posted

技术标签:

【中文标题】何时或为啥要使用右外连接而不是左连接?【英文标题】:When or why would you use a right outer join instead of left?何时或为什么要使用右外连接而不是左连接? 【发布时间】:2010-09-30 23:36:07 【问题描述】:

Wikipedia 状态:

“在实践中,很少使用显式右外连接,因为它们总是可以替换为左外连接并且不提供额外功能。”

谁能提供他们更喜欢使用 RIGHT 表示法的情况,为什么? 我想不出使用它的理由。对我来说,它永远不会让事情变得更清楚。

编辑: 我是一名 Oracle 资深人士,我制定了新年决心,让自己摆脱 (+) 语法。我想把它做好

【问题讨论】:

或者,换一种说法,你想左右(和完整)做:) 可以,当然,但正确吗?归结为开发人员对右外连接的理解有多么有限。它们不一样,否则它们将不存在。 #叹息 可以达到同样的效果。由于“A Left Join B”等同于“B right join A”,唯一的区别是列的顺序会在输出中改变。 这里的例子***.com/a/7313507/73226 【参考方案1】:

我能想到使用 RIGHT OUTER JOIN 的唯一原因是尝试使您的 SQL 更具自我记录性。

您可能希望对在一对多关系的从属(多)侧具有空行的查询使用左连接,对在独立侧生成空行的查询使用右连接。

这也可能发生在生成的代码中,或者如果商店的编码要求在 FROM 子句中指定了表的声明顺序。

【讨论】:

+1,如果它总结了您、Michael 和 Ivan 的答案,将接受答案。 我们可以使用左外连接获得相同的结果(顺便说一下我们使用右外连接)。那么为什么有右连接选项,反之亦然?。【参考方案2】:

B RIGHT JOIN A 与 A LEFT JOIN B 相同

B RIGHT JOIN A 读作:B ON RIGHT, THEN JOINS A. 表示 A 在数据集的左侧。和 A LEFT JOIN B 一样

如果您将 LEFT JOIN 重新排列为 RIGHT,则无法获得任何性能。

我能想到为什么要使用 RIGHT JOIN 的唯一原因是,如果您是那种喜欢从内而外思考的人(从详细信息右连接标题中选择 *)。就像其他人喜欢 little-endian,其他人喜欢 big-endian,其他人喜欢自上而下设计,其他人喜欢自下而上设计。

另一种情况是,如果您已经有一个庞大的查询要添加另一个表,而重新排列查询很麻烦,那么只需使用 RIGHT JOIN 将表插入现有查询。

【讨论】:

+1,如果它总结了您、Jekke 和 Ivan 的答案,将接受答案。 没有获得任何性能...这不是学习按预期使用该语言的好理由。如果出于性能原因一切都已完成,那么 ruby​​ 和 php 和 .net 将不再存在。 是的,同意最后一段。这可能是一个正当的理由——但我敢打赌,在这种情况下,产生不可维护的代码是一种相当糟糕的做法......【参考方案3】:

我以前从未使用过right join,也从未想过我真的需要它,这似乎有点不自然。但是经过我的思考,它在需要外连接一个表和多个表的交集的情况下真的很有用,所以你有这样的表:

想要得到这样的结果:

或者,在 SQL(MS SQL Server)中:

declare @temp_a table (id int)
declare @temp_b table (id int)
declare @temp_c table (id int)
declare @temp_d table (id int)

insert into @temp_a
select 1 union all
select 2 union all
select 3 union all
select 4

insert into @temp_b
select 2 union all
select 3 union all
select 5

insert into @temp_c
select 1 union all
select 2 union all
select 4

insert into @temp_d
select id from @temp_a
union
select id from @temp_b
union
select id from @temp_c

select *
from @temp_a as a
    inner join @temp_b as b on b.id = a.id
    inner join @temp_c as c on c.id = a.id
    right outer join @temp_d as d on d.id = a.id

id          id          id          id
----------- ----------- ----------- -----------
NULL        NULL        NULL        1
2           2           2           2
NULL        NULL        NULL        3
NULL        NULL        NULL        4
NULL        NULL        NULL        5

所以如果切换到left join,结果会不一样。

select *
from @temp_d as d
    left outer join @temp_a as a on a.id = d.id
    left outer join @temp_b as b on b.id = d.id
    left outer join @temp_c as c on c.id = d.id

id          id          id          id
----------- ----------- ----------- -----------
1           1           NULL        1
2           2           2           2
3           3           3           NULL
4           4           NULL        4
5           NULL        5           NULL

没有正确连接的唯一方法是使用公用表表达式或子查询

select *
from @temp_d as d
    left outer join (
        select *
        from @temp_a as a
            inner join @temp_b as b on b.id = a.id
            inner join @temp_c as c on c.id = a.id
    ) as q on ...

【讨论】:

你不需要嵌套一个 SELECT,你可以嵌套一个连接:FROM @temp_d AS d LEFT OUTER JOIN (temp_a AS a INNER JOIN @temp_b AS b ON b.id = a.id INNER JOIN @temp_c AS c ON c.id = a.id) ON a.id = d.id。 (括号是不必要的,它们只是为了可读性而添加的。)但是,确实有些人不确定他们更讨厌哪种语法,嵌套连接或右外连接,所以右连接可能会起作用 对他们来说不那么糟糕。 :) 很好,我也从未使用过嵌套连接语法 :) 实际上,最后一个以 d 作为主表的查询看起来更具可读性——“一个表是外连接的,而一堆表之间是内连接的。” 如果查询以“select * from a”开头,则该表听起来像主表。当序列中稍后的某个表开始在主表中戳洞时,这看起来很奇怪。 另外,在以下加入“on”部分中可以引用哪些列?只有“主”表,还是前面的任何表?我没有考虑这么多。【参考方案4】:

我唯一会想到右外连接的情况是,如果我正在修复一个完全连接,并且碰巧我需要结果来包含右侧表中的所有记录。尽管我很懒惰,但我可能会很生气,以至于我会重新排列它以使用左连接。

Wikipedia 的这个例子说明了我的意思:

SELECT *  
FROM   employee 
   FULL OUTER JOIN department 
      ON employee.DepartmentID = department.DepartmentID

如果您只是将单词FULL 替换为RIGHT,您将获得一个新查询,而无需交换ON 子句的顺序。

【讨论】:

FULL 语句最初是如何到达那里的?写得不好的混淆查询? FULL 有它的目的,并不总是需要“修复”,用RIGHT 替换它不会做同样的事情。如果您正在构建一个报告来帮助公司验证员工-部门分配,并希望包括没有员工的部门以及尚未分配到部门的员工,该怎么办?【参考方案5】:
SELECT * FROM table1 [BLANK] OUTER JOIN table2 ON table1.col = table2.col

将 [BLANK] 替换为:

LEFT - 如果您想要 table1 中的所有记录,即使它们没有与 table2 匹配的 col(也包括匹配的 table2 记录)

RIGHT - 如果您想要 table2 中的所有记录,即使它们没有与 table1 匹配的 col(也包括与 table1 匹配的记录)

FULL - 如果您想要 table1 和 table2 中的所有记录

大家都在说什么?他们是一样的吗?我不这么认为。

【讨论】:

您始终可以将右外连接替换为产生相同答案的左外连接,反之亦然。 你的意思是你只是换掉了“LEFT”和“RIGHT”这两个词,还是你的意思是你在查询的语法上翻来覆去? 您还必须更改联接中表的顺序。 @Andrew:后者。人们总是可以用等价的左外连接来表达给定的右外连接,例如,select ... from a right outer join b using(x);可以表示为 select ... from b left outer join a using(x);因此问题是,为什么要使用 RIGHT OUTER JOIN? 我同意 RIGHT OUTER JOIN 很少使用,但是说它们相同对于 SQL 和 JOIN 新手来说是非常误导的。我认为我唯一一次使用 ROJ 是在 MS Access“查询”上——真是一场噩梦:/【参考方案6】:
SELECT * FROM table_a
INNER JOIN table_b ON ....
RIGHT JOIN table_c ON ....

在确保始终选择 table_c 中的所有行的同时,您还能如何快速/轻松地内部连接前 2 个表并与 table_c 连接?

【讨论】:

您可以先列出 table_c,然后将其加入其他人。 写出来,@Matt 的语法似乎比等效的语法更具可读性:SELECT * FROM table_c LEFT JOIN ( SELECT * FROM table_a INNER JOIN table_b ON .... ) ON .... 【参考方案7】:

我真的不需要对正确的连接进行太多思考,但我想在近 20 年的 SQL 查询编写中,我还没有遇到过使用它的合理理由。我当然见过很多我猜想是由于开发人员使用内置查询构建器的地方。

每当我遇到一个问题时,我都会重写查询以消除它 - 我发现如果您已经有一段时间没有访问该查询,那么它们只是需要太多额外的精神能量来学习或重新学习,并且查询的意图丢失或返回不正确的结果并不少见 - 通常这种不正确导致我要求检查查询为什么不起作用。

考虑到这一点,一旦你引入了右连接,你现在就有了我认为需要在中间相遇的竞争逻辑分支。如果引入了额外的要求/条件,这两个分支可能会进一步扩展,您现在需要处理更多复杂性,以确保一个分支不会产生不正确的结果。

此外,一旦您引入了右连接,稍后处理查询的其他经验不足的开发人员可能会简单地将附加表添加到查询的右连接部分,这样做会扩展仍然需要的竞争逻辑流在中间相遇;或者在我见过的某些情况下,开始嵌套视图是因为他们不想触及原始逻辑,这可能部分是因为他们可能不理解驱动逻辑的查询或业务规则。

【讨论】:

当时没看上面的评论吗?程序员的想法是不是很奇怪,因为他们没有使用过一些多余的东西,而事实上,也许他们应该更新他们的技能来理解边缘情况。【参考方案8】:

SQL 语句除了正确之外,还应该尽可能易于阅读和表达简洁(因为它们代表单个原子操作,您需要完全理解它们以避免意外后果。)有时表达式更用右外连接明确说明。

但是一个总是可以转换成另一个,优化器会像另一个一样做。

在相当长的一段时间里,至少有一个主要的 rdbms 产品只支持 LEFT OUTER JOIN。 (我相信是 mysql。)

【讨论】:

"有时使用右外连接可以更清楚地说明表达式。"我正在为可能的情况而苦苦挣扎。为什么要使用一种基本上与另一种更常用的相反的语法?你有例子吗? 不。我自己从未使用过 RIGHT OUTER JOIN :D.【参考方案9】:

我使用右连接的唯一情况是,当我想查看两组数据时,我已经从之前编写的查询中获得了左连接或内连接的特定顺序的连接。在这种情况下,假设您希望将未包含在表 a 中但包含在表 b 中的记录视为一组数据,而在另一组数据中将记录不在表 b 中但在表 a 中。即使这样,我也倾向于这样做只是为了节省研究时间,但如果是要运行多次的代码,我会更改它。

【讨论】:

【参考方案10】:

在某些 SQL 数据库中,有优化器提示告诉优化器按照它们在 FROM 子句中出现的顺序连接表 - 例如/*+ORDERED */ 在 Oracle 中。在一些简单的实现中,这甚至可能是唯一可用的执行计划。

在这种情况下,FROM 子句中的表顺序很重要,因此RIGHT JOIN 可能很有用。

【讨论】:

【参考方案11】:

我认为在这种情况下如果你没有正确的加入是很困难的。前与甲骨文。

with a as(
     select 1 id, 'a' name from dual union all
     select 2 id, 'b' name from dual union all
     select 3 id, 'c' name from dual union all
     select 4 id, 'd' name from dual union all
     select 5 id, 'e' name from dual union all
     select 6 id, 'f' name from dual 
), bx as(
   select 1 id, 'fa' f from dual union all
   select 3 id, 'fb' f from dual union all
   select 6 id, 'f' f from dual union all
   select 6 id, 'fc' f from dual 
)
select a.*, b.f, x.f
from a left join bx b on a.id = b.id
right join bx x on a.id = x.id
order by a.id

【讨论】:

select a.*, b.f, x.f from bx x left outer join a on a.id = x.id left join bx b on b.id = a.id order by a.id

以上是关于何时或为啥要使用右外连接而不是左连接?的主要内容,如果未能解决你的问题,请参考以下文章

内连接左外连接右外连接交叉连接区别

内连接左外连接右外连接交叉连接区别

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

mysql数据库的左连接,右连接,内链接。有何区别

SQL:内连接左外连接右外连接全连接交叉连接区别

数据库左连接右连接全联接左外右外全外