【问题标题】:LEFT JOIN returns same result as INNER JOINLEFT JOIN 返回与 INNER JOIN 相同的结果
【发布时间】:2014-11-15 06:15:33
【问题描述】:

我有一张桌子(磨砂),里面有 1600 件独特的物品。第二张桌子有 100 万多。我运行我的 INNER JOIN 并获得 65 个匹配项:

SELECT a.`BW Parent Number` , a.`Vendor Name`, b.`Parent Supplier Name` 
FROM `scrubs` AS a
JOIN pdwspend AS b ON a.`BW Parent Number` = b.`Child Supplier ID`
WHERE a.`year` =2014
AND b.`BU ID` = 'BU_1'
AND b.version LIKE '%GOV%'
GROUP BY a.`BW Parent Number` 

然后我运行 LEFT OUTER JOIN,得到相同的 65 个结果:

SELECT a.`BW Parent Number` , a.`Vendor Name`, b.`Parent Supplier Name`  
FROM `scrubs` AS a
LEFT OUTER JOIN pdwspend AS b ON a.`BW Parent Number` = b.`Child Supplier ID` 
WHERE a.`year` =2014
AND b.`BU ID` = 'BU_1'
AND b.version LIKE '%GOV%'
GROUP BY a.`BW Parent Number`

为什么不将左表中的所有行都带入并为 b.Parent Supplier Name 下不匹配的行显示 NULL ?

谢谢!

【问题讨论】:

    标签: mysql sql join left-join


    【解决方案1】:

    为什么不把左表的所有行都带进来,不匹配的行显示为 NULL?

    您的LEFT JOIN 没有按预期工作的原因是WHERE 子句中该表的条件;这有时称为“隐式内部连接”。

    这最好通过演示来解释。下面是2个简单的表格

        | USER_ID | FIRST_NAME |  LAST_NAME |
        |---------|------------|------------|
        |     123 |       Fred | Flintstone |
        |     456 |     Barney |     Rubble |
    
        |    ID | USER_ID |       NOTE_BODY |
        |-------|---------|-----------------|
        | 98765 |     123 | Yabba Dabba Doo |
    

    正如您所料,INNER JOIN 只产生一行,其中 User_ID 值在两个表中都匹配。

    SELECT * FROM users u INNER JOIN user_notes n ON u.User_ID = n.User_ID;

        | USER_ID | FIRST_NAME |  LAST_NAME |    ID |       NOTE_BODY |
        |---------|------------|------------|-------|-----------------|
        |     123 |       Fred | Flintstone | 98765 | Yabba Dabba Doo |
    

    通过更改为 LEFT JOIN,我们获得了用户中的所有记录,但并非所有记录都具有来自 User_Notes 的信息,因此我们在这些列中获得了 NULL

    SELECT * FROM users u LEFT JOIN user_notes n ON u.User_ID = n.User_ID;

        | USER_ID | FIRST_NAME |  LAST_NAME |     ID |       NOTE_BODY |
        |---------|------------|------------|--------|-----------------|
        |     123 |       Fred | Flintstone |  98765 | Yabba Dabba Doo |
        |     456 |     Barney |     Rubble | (null) |          (null) |
    

    但是,如果我们真的只想要连接表中的一些记录,会发生什么?

    SELECT * FROM users u LEFT JOIN user_notes n ON u.User_ID = n.User_ID WHERE n.Note_Body = 'Yabba Dabba Doo';

        | USER_ID | FIRST_NAME |  LAST_NAME |    ID |       NOTE_BODY |
        |---------|------------|------------|-------|-----------------|
        |     123 |       Fred | Flintstone | 98765 | Yabba Dabba Doo |
    

    好吧,如果我们使用 WHERE 条件,效果与 INNER JOIN 相同,现在我们不会获取所有用户记录,这是一个隐式内部连接。

    我们没有获得所有用户记录的原因是因为我们现在坚持所有结果行必须在可能为 NULL 的列中具有特定值。因此,我们可以更改 WHERE 条件以允许 NULL。

    SELECT * FROM users u LEFT JOIN user_notes n ON u.User_ID = n.User_ID WHERE (n.Note_Body = 'Yabba Dabba Doo' OR n.Note_Body 为空);

        | USER_ID | FIRST_NAME |  LAST_NAME |     ID |       NOTE_BODY |
        |---------|------------|------------|--------|-----------------|
        |     123 |       Fred | Flintstone |  98765 | Yabba Dabba Doo |
        |     456 |     Barney |     Rubble | (null) |          (null) |
    

    或

    我们添加到连接条件(即在 ON 之后)而不是在连接表上使用 WHERE 子句

    SELECT * FROM users u LEFT JOIN user_notes n ON u.User_ID = n.User_ID AND n.Note_Body = 'Yabba Dabba Doo';

        | USER_ID | FIRST_NAME |  LAST_NAME |     ID |       NOTE_BODY |
        |---------|------------|------------|--------|-----------------|
        |     123 |       Fred | Flintstone |  98765 | Yabba Dabba Doo |
        |     456 |     Barney |     Rubble | (null) |          (null) |
    

    因此,在使用外连接时要小心,因为 where 子句不会覆盖外连接允许的 NULL。

    See the above as a SQLFiddle demonstration

    【讨论】:

    • 感谢您的回复!很有用
    【解决方案2】:

    因为您没有使用 on 子句。改成:

    SELECT a.`BW Parent Number`, a.`Vendor Name`, b.`Parent Supplier Name`
      FROM scrubs AS a
      LEFT OUTER JOIN pdwspend AS b
        ON a.`BW Parent Number` = b.`Child Supplier ID`
       and b.`BU ID` = 'BU_1'
       AND b.`version` LIKE '%GOV%'
     WHERE a.`year` = 2014
    

    另外,group by 也没有任何意义。如果您正在聚合某些内容,则可以使用 group by 子句。

    根据您对重复行的评论,这可能是因为您名为“pdwspend”的表对于每个“子供应商 ID”都有不止一行。这是您加入“scrubs”表的唯一字段。所以是的,对于 pdwspend 上的每个匹配行,您将拥有与第二个表上一样多的行(该表上可能还有其他列,因此它们实际上不是“重复”行,您只是没有选择足够的列来说明)。

    因为您只对选定数量的列感兴趣,并且不希望根据这些列“重复”行,您可以尝试使用以下方式区分:

    (您在 cmets 中输入的查询中出现错误的原因是因为您的内联视图(from 子句中的子查询)没有选择“父供应商名称”字段,所以是的,它没有存在于该内联视图中,因为您没有将其添加到该内联视图的选择列表中。

         select a.`BW Parent Number`, a.`Vendor Name`, b.`Parent Supplier Name`
           from scrubs a
      left join ( select distinct `Child Supplier ID`, `Parent Supplier Name`
                             from pdwspend
                            where `BU ID` = 'BU_1'
                              and `version` LIKE '%GOV') b
             on a.`BW Parent Number` = b.`Child Supplier ID`
          where a.`year` = 2014
    

    【讨论】:

    • 发生的情况是表 pdwspend 中的每个 b.Child Supplier ID 可能会出现数百次。当我没有它加入时,它会带来每一个匹配,所以我有很多重复的行。我认为更好的解决方案可能在这行内......这也给了我一个错误!:
    • SELECT a.BW Parent Number, a.Vendor Name, b.Parent Supplier Name FROM 作为左外连接(SELECT DISTINCT Child Supplier ID FROM pdwspend WHERE year =2014 和 @987654329 @ = 'BU_1' AND version LIKE '%GOV%' ) AS b ON a.BW Parent Number = b.Child Supplier ID WHERE a.year = 2014 #1054 - '中的未知列'b.Parent Supplier Name'字段列表'
    • 您没有在select distinct subquery 中包含b.Parent Supplier Name。重新查看 Brian 的查询并复制它
    猜你喜欢
    • 2019-04-16
    • 1970-01-01
    • 2017-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    相关资源
    最近更新 更多