LEFT JOIN返回与INNER JOIN相同的结果

时间:2014-09-21 00:04:25

标签: mysql sql join left-join

我有一张桌子(磨砂),有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?

谢谢!

2 个答案:

答案 0 :(得分:10)

因为您没有使用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子句。

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

因为您只对选定数量的列感兴趣,并且不希望基于这些列重复行,您可以尝试使用以下列:

(你在评论中输入错误的原因是你的内联视图 - 你的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

答案 1 :(得分:9)

为什么不从左表中提取所有行并为不匹配的行显示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 IS NULL );

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

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

  

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