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

问题描述 投票:0回答:14

我有一个非常基本的

LEFT OUTER JOIN
来返回左表中的所有结果以及来自更大表的一些附加信息。左表包含 4935 条记录,但当我将其 LEFT OUTER JOIN 到另一个表时,记录数明显更大。

据我所知,

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
的理解不完整,希望有人可以解释这是如何发生的?

sql sql-server sql-server-2005 t-sql
14个回答
262
投票

LEFT OUTER JOIN 将返回左表中与右表(如果可能)连接的所有记录。

但是,如果存在匹配项,它仍会返回 所有匹配的行。 因此,左表中的一行与右表中的两行匹配将返回为 两行,就像 INNER JOIN 一样。


查看针对此特定问题的编辑查询,您似乎只从左侧表返回数据。因此,如果您只需要 LEFT 表中的数据,并且只希望 LEFT 表中的每一行返回一行,那么您根本不需要执行 JOIN,只需直接从 LEFT 表执行 SELECT 即可。


196
投票
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

62
投票

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


21
投票

针对你的后记,这取决于你想要什么。

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

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

如果您只查看外连接中的 1 或 2 列,您可能会考虑使用标量子查询,因为您将保证得到 1 个结果。


15
投票

左表中的每条记录将返回与右表中的匹配记录一样多的次数——至少 1 次,但很可能会超过 1 次。


10
投票

如果您只需要右侧任意一行

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
)

9
投票

左右表会不会是一对多的关系?


8
投票

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

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


5
投票

请注意,如果在包含左外连接的查询的“右侧”表上有一个 where 子句... 如果右侧没有满足where子句的记录,那么左侧表的相应记录将不会出现在您的查询结果中......


2
投票

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


2
投票

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


1
投票

查询返回的行数比左表(在您的情况下为

SUSP.Susp_Visits
)更多的唯一方法是条件 (
SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum
) 匹配右表中的多行,即
DATA.Dim_Member
。因此,
DATA.Dim_Member
中有多行,其中
DATA.Dim_Member.MembershipNum
存在相同的值。您可以通过执行以下查询来验证这一点:

select DATA.Dim_Member.MembershipNum, count(DATA.Dim_Member.MembershipNum) from DATA.Dim_Member group by DATA.Dim_Member.MembershipNum


0
投票

由于左表包含 4935 条记录,我怀疑您希望结果返回 4935 条记录。试试这个:

create table table1
(siteID int, 
SuspReason int)

create table table2
(siteID int, 
SuspReason int)

insert into table1(siteID, SuspReason) values 
(1, 678), 
(1, 186), 
(1, 723)
    
insert into table2(siteID, SuspReason) values 
(1, 678),
(1, 965)
   
select distinct t1.siteID, t1.SuspReason
from table1 t1 left join table2 t2 on t1.siteID = t2.siteID and t1.SuspReason = t2.SuspReason

union 

select distinct t2.siteID, t2.SuspReason 
from table1 t1 right join table2 t2 on t1.siteID = t2.siteID and t1.SuspReason = t2.SuspReason

0
投票

简单来说,LEFT OUTER JOIN 是每个连接键内的笛卡尔积,以及左表中不匹配的行 (即对于每个在 table_L 中有 N 条记录、在 table_R 中有 M 条记录的 key_x,如果 M>0,则结果将有 N*M 条记录,如果 M=0,则结果将有 N 条记录)

© www.soinside.com 2019 - 2024. All rights reserved.