【问题标题】:How can a LEFT OUTER JOIN return more records than exist in the left table?LEFT OUTER JOIN 如何返回比左表中更多的记录?
【发布时间】:2010-10-29 07:41:59
【问题描述】:

我有一个非常基本的 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 的理解不完整,希望有人能解释一下这是怎么发生的?

后记

感谢您的精彩回答,我对 LEFT OUTER JOINS 的理解现在好多了,但是有人可以建议一种可以修改此查询的方法,以便我只返回左表中存在的尽可能多的记录吗?

此查询纯粹是为了生成报告,重复匹配只会混淆问题。

/后记

【问题讨论】:

  • 要“获取与左表中存在的记录一样多的记录”,如果有多个匹配项,您需要指定从右侧开始选择哪一行。
  • 你如何指定这个?我希望返回第一个匹配项。
  • 你必须定义第一个匹配的含义。您想要最早的记录,id 最高的记录还是什么?
  • 如果与附加表中的主键匹配,则说明正确。
  • 在构建查询时,我经常使用this 之类的资源作为备忘单。如果链接失效,只需 google sql join;它们是不同类型连接的维恩图。

标签: sql sql-server sql-server-2005 tsql


【解决方案1】:

LEFT OUTER JOIN 将返回 LEFT 表中的所有记录,并尽可能与 RIGHT 表连接。

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

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

【讨论】:

  • 加入右表的原因是我只从左边得到了右表至少有一条记录的记录,但非常感谢您的解释。
【解决方案2】:
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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • RIGHT JOIN 或 FULL JOIN 会发生另一种情况?
    【解决方案4】:

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

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

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

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

    【讨论】:

    • 这是一个很好的答案,因为它提供了有关如何仅从左表返回行的建议。
    • Alternatively, depending on what you actually want you can use aggregate functions (if for example you just want a string from the right part you could generate a column that is a comma delimited string of the right side results for that left row. 这正是我想要实现的目标,但还没有弄清楚如何实现。
    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

      左右表之间可以是一对多的关系吗?

      【讨论】:

        【解决方案7】:

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

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

        【讨论】:

        • 我开始想当行数等于 N x M 时,我想到的唯一真实情况是当 N 或 M 等于 1 时。你同意吗?
        • 不,我不知道。您不应仅将连接条件视为键相等连接。它可以是任意条件,例如日期范围、不等式等 两种极端情况: (a) N 行在 M 行中没有一个匹配项,然后左外连接导致 N 行与 NULL 匹配。 (b) N 行中的每一行都匹配所有 M 行,则结果为 N x M 行集合。
        • 你说得对,我只考虑键相等的连接。我喜欢你在“案例 b”中的例子。我相信“N 行中的每一行都匹配所有 M 行”是返回 N x M 行时的通用方法,仅考虑键相等时这是相当不可能的。
        【解决方案8】:

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

        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
        )
        

        【讨论】:

        • 因为你没有提供DDL和DML,所以我没有测试。无论如何,我认为 EXISTS 是你想要的。试试这个: SELECT SuspReason, SiteID FROM( SELECT SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID, ROW_NUMBER() OVER(PARTITION BY SUSP.Susp_Visits.SiteID ORDER BY SUSP.Susp_Visits.SiteID) AS rn FROM SUSP.Susp_Visits LEFT OUTER加入 DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum ) AS t WHERE rn=1
        【解决方案9】:

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

        【讨论】:

        • 您应该将条件添加到相应的 LEFT OUTER JOIN 的 ON 子句中。
        • WHERE 子句不是SELECT 语句的“右侧”或“左侧”的一部分,它属于所有连接的集合,因此适用于所有联接(即,加入后,而不是加入)。就像@Mik 所说,仅适用于“左侧”或“右侧”的此类条件应该是JOIN 语句的ON 子句的一部分。
        【解决方案10】:

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

        【讨论】:

          【解决方案11】:

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

          【讨论】:

            【解决方案12】:

            由于左表包含 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
            

            【讨论】:

            • 问题是关于两个具有不同列的表,其中一个向另一个添加辅助数据。您正在做的是将联合应用于具有相同结构的两个表,这不是 OP 问题中发生的情况。
            【解决方案13】:

            您的查询将返回比左表更多的行数(在您的情况下为 SUSP.Susp_Visits)的唯一方法是条件 (SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum) 匹配右表中的多行,即 @ 987654323@。因此,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

            【讨论】:

              猜你喜欢
              • 2023-02-10
              • 2014-11-12
              • 2023-03-09
              • 1970-01-01
              • 2011-08-20
              • 1970-01-01
              • 2015-12-21
              • 2012-06-21
              • 2014-05-08
              相关资源
              最近更新 更多