【问题标题】:Opposite of inner join与内连接相反
【发布时间】:2011-03-26 03:50:16
【问题描述】:

内连接的反面是什么?对于表 Person (int PersonId, varchar PersoName, int AddrId),我想知道在 Person with bad AddrId 中没有在 Address 表中的行。

【问题讨论】:

    标签: sql database


    【解决方案1】:

    内连接与外连接不同。它们服务于不同的目的。但是,从一个表中查找另一个表中不存在的行的常见模式是使用外连接:

    Select ...
    From Table1
        Left Join Table2
            On Table2.ForeignKeyCol = Table1.PrimaryKeyCol
    Where Table2.PrimaryKeyCol Is Null
    

    这将返回 Table1 中的所有行和 Table2 中的任何匹配行,这样如果给定的 Table1 行没有 Table2 匹配,则返回 Table2 列的空值。然后要求不可为空的列 (Table2.PrimaryKeyCol) 为 Null,我将从 Table1 中获取 Table2 中不存在的所有行。使用您的示例表名,我们将有如下内容:

    Select ...
    From Person
        Left Join Address
            On Address.PersonId = Person.Id
    Where Address.Id Is Null
    

    【讨论】:

      【解决方案2】:

      内连接的反面是什么?

      一个 OUTER join,可以是三个选项:

      • 正确
      • 已满

      This is a good visual representation of JOINs

      我想知道地址表中没有行的 Person with bad AddrId 中的行。

      使用 LEFT JOIN/IS NULL

         SELECT p.*
           FROM PERSON p
      LEFT JOIN ADDRESS a ON a.addrid = p.addrid
          WHERE a.addrid IS NULL
      

      使用不存在

      SELECT p.*
        FROM PERSON p
       WHERE NOT EXISTS(SELECT NULL
                          FROM ADDRESS a
                         WHERE a.addrid = p.addrid)
      

      使用 NOT IN

      SELECT p.*
        FROM PERSON p
       WHERE p.addrid NOT IN (SELECT a.addrid
                                FROM ADDRESS a)
      

      【讨论】:

      • +1 以完整地回答如何在具有错误 AddrId 的 Person 中查找行。 OTOH,我不认为外部联接是 相反 内部联接。只是不同。
      • @Shannon Severance:同意 - 这就是我投票支持 Thomas 答案的原因。
      • +1 呵呵。我认为您应该对精美的格式、完整性和 Jeff 的精美维恩图表示赞同。
      • 这是一个很好的回应,我唯一要补充的(正如我在不太全面的回应中所尝试的那样:-P)是这些方法对 Left Join / IS NULL 有不同的性能影响最快的假设你正在加入索引列。
      • @Zugwalt:谢谢,但是LEFT JOIN/IS NULL is the fastest only on MySQL, assuming the columns can't be NULL。任何其他数据库都不是这种情况。
      【解决方案3】:

      我认为最好的解决方案是使用EXISTS。像这样:

      SELECT * FROM Person P
      WHERE P.AddrId IS NOT NULL 
        AND NOT EXISTS ( SELECT 1 FROM Address A WHERE A.AddrId = P.AddrId )
      

      上面的查询将返回每个设置了 AddrId 但在 Address 表中没有对应记录的人。

      Obs.:EXISTS查询中使用常量1来避免表访问。

      【讨论】:

        【解决方案4】:

        如果您将内连接视为满足特定条件的两个表的行,那么相反的情况是 either 表中不满足特定条件的行。

        例如,以下将选择地址表中具有地址的所有人员:

        SELECT p.PersonName, a.Address
        FROM people p
        JOIN addresses a
            ON p.addressId = a.addressId
        

        我想与此“相反”的做法是选择所有没有地址的人和所有没有人的地址。但是,这似乎不是您要问的,您似乎只对其中的一个组成部分感兴趣:地址表中没有地址的所有人。

        为此,最好使用左连接:

        SELECT p.PersonName
        FROM people p
        LEFT JOIN addresses a
           ON p.addressId = a.addressId
        WHERE a.addressId IS NULL
        

        请注意,通常有些人更喜欢以不同的方式编写它,因为他们认为它更具可读性(但是根据我使用大型表的经验,它的性能比上述方式差):

        SELECT PersonName
        FROM people
        WHERE addressId NOT IN (SELECT addressId FROM addresses)
        

        【讨论】:

        • 由于我的原因,您 LEFT JOIN 使我的查询崩溃导致 tmp 文件夹中没有可用空间。最后一个用 NOT EXISTS 替换 NOT IN 的解决方案可以正常工作。
        猜你喜欢
        • 2011-05-01
        • 2010-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-06
        • 1970-01-01
        • 2013-09-29
        • 1970-01-01
        相关资源
        最近更新 更多