LEFT OUTER JOIN如何返回比左表中更多的记录?


164

我有一个非常基本的LEFT OUTER JOIN,可以从左表中返回所有结果,并从更大的表中返回一些其他信息。左表包含4935条记录,但是当我将其左移到另一个表中时,记录数会大大增加。

据我所知,绝对的福音是,LEFT OUTER JOIN将返回左表中的所有记录,并返回右表中的匹配记录,并为所有无法匹配的行返回空值,因此,我的理解是返回的行数不可能超过左表中存在的行数,但是这都是一样的!

SQL查询如下:

SELECT     SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID
FROM         SUSP.Susp_Visits LEFT OUTER JOIN
                      DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum

也许我在语法上犯了一个错误,或者我对LEFT OUTER JOIN的理解不完整,希望有人能解释这是怎么发生的?

后记

感谢您提供的出色答案,现在我对LEFT OUTER JOINS的了解要好得多,但是有人可以建议修改此查询的方式,以便使我只获得与左表中一样多的返回记录吗?

此查询纯粹是为了生成报告,重复的匹配项只会使事情变得混乱。

/后记


5
要“获得与左表中一样多的返回记录”,您需要从右侧指定要选择是否有多个匹配项的行。
AK 2009年

1
您如何指定呢?我希望第一场比赛能归还。
西蒙·克罗斯

1
您必须定义第一个匹配的含义。您想要最早的记录,还是ID最高的记录?
HLGEM 2013年

1
如果您与附加表中的主键匹配,则说明正确。
普雷格斯(Prageeth)Godage '15

我经常使用类似的资源建立查询时的小抄。如果链接消失,则只需google sql join ; 它们是不同连接类型的维恩图。
Zimano

Answers:


189

LEFT OUTER JOIN将返回LEFT表中与RIGHT表连接的所有记录。

如果存在匹配项,它仍将返回所有匹配的行,因此,LEFT中的一行与RIGHT中的两行匹配将作为两个ROWS返回,就像INNER JOIN一样。

编辑:作为对您的编辑的回应,我只是进一步查询了您的查询,看来您只是从LEFT表返回数据。因此,如果只希望从LEFT表中获取数据,并且只希望LEFT表中的每一行返回一行,那么您根本就不需要执行JOIN,而可以直接从LEFT表中进行SELECT。


1
加入右表的原因是,所以我仅从左表中获得记录,而在右表中至少有一条记录,但是非常感谢您的解释。
杰伊·王尔德

125
Table1                Table2
_______               _________
1                      2
2                      2
3                      5
4                      6

SELECT Table1.Id, Table2.Id FROM Table1 LEFT OUTER JOIN Table2 ON Table1.Id=Table2.Id

结果:

1,null
2,2
2,2
3,null
4,null

1
如此简单,却如此强大。
kiradotee

39

这不是不可能的。左表中的记录数是它将返回的最小记录数。如果右表中有两条记录与左表中的一条记录匹配,它将返回两条记录。


12

根据您的后记,这取决于您的意愿。

您的左表中的每一行都有(可能)多行,因为联接条件有多个匹配项。如果希望总结果的行数与查询左侧的行数相同,则需要确保联接条件导致一对一匹配。

或者,根据实际需要,可以使用聚合函数(例如,如果您只想从右侧输入一个字符串,则可以生成一列,该列是该左行右侧结果的逗号分隔字符串。

如果仅从外部联接中查看1或2列,则可以考虑使用标量子查询,因为可以保证得到1个结果。


4
这是一个很好的答案,因为它提供了有关如何仅返回左表中的行的建议。
卡恩斯

9

左表中的每个记录将被返回与右表中的匹配记录一样多的次数-至少为1,但很容易超过1。


8

像INNER JOIN(普通联接)一样,LEFT OUTER JOIN将为左表中的每一行返回与在右表中找到的匹配项一样多的结果。因此,您可以得到很多结果-多达N x M,其中N是左表中的行数,M是右表中的行数。

在LEFT OUTER JOIN中始终保证最小结果数至少为N。


1
我开始考虑当行数等于N x M时,我想到的唯一真实情况是N或M等于1。您同意吗?
BartoszMiller

2
不,我不知道 您不应将联接条件视为仅键相等联接。它可以是任意条件,例如日期范围,不平等等。两种极端情况:(a)N行在M行中没有单个匹配项,因此左外连接导致N行与NULL匹配。(b)N行中的每行都与M行中的所有行匹配,则结果是设置了N x M行。
topchef

1
没错,我在考虑仅在键相等性方面进行联接。我喜欢您的“案例b”中的示例。我相信“返回N行中的每行都与所有M行中的所有行”是返回N x M行时的通用方法,当仅考虑键相等性时,这几乎是无法想象的。
BartoszMiller


6

请注意,如果在包含左侧外部联接的查询的“右侧”表上具有where子句...如果右侧没有满足where子句的记录,则对应“左侧”的记录'表格不会出现在您的查询结果中。...


1
然后,应将条件添加到相应的LEFT OUTER JOIN的ON子句中。
米克

6

如果您只需要右侧的任何一行

SELECT SuspReason, SiteID FROM(
    SELECT SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID, ROW_NUMBER()
    OVER(PARTITION BY SUSP.Susp_Visits.SiteID) AS rn
    FROM SUSP.Susp_Visits
    LEFT OUTER JOIN DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum
) AS t
WHERE rn=1

要不就

SELECT SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID
FROM SUSP.Susp_Visits WHERE EXISTS(
    SELECT DATA.Dim_Member WHERE SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum
)

1
因为您没有提供DDL和DML,所以我没有进行测试。无论如何,我认为EXISTS是您想要的。尝试以下操作:SELECT SuspReason,SiteID FROM(SELECT SUSP.Susp_Visits.SuspReason,SUSP.Susp_Visits.SiteID,ROW_NUMBER()OVER(由SUSP.Susp_Visits.SiteID排序由SUSP.Susp_Visits.SiteID排序)从SUSP到SUSP。在SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum上加入DATA.Dim_Member)在rn = 1的位置
AK

2

似乎每个SUSP.Susp_Visits行的DATA.Dim_Member表中有多个行。


2

如果Dim_Member中的多(x)行与Susp_Visits中的单行相关联,则resul集中将有x行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.