何时使用LEFT JOIN和何时使用INNER JOIN?

45

我觉得我一直被教导使用LEFT JOIN,我经常看到它们与INNER混合在一起以完成相同类型的查询,这些查询在不同页面上执行相同的操作。下面是代码:

SELECT ac.reac, pt.pt_name, soc.soc_name, pt.pt_soc_code
FROM
  AECounts ac
  INNER JOIN 1_low_level_term llt on ac.reac = llt.llt_name
  LEFT JOIN 1_pref_term pt ON llt.pt_code = pt.pt_code
  LEFT JOIN 1_soc_term soc ON pt.pt_soc_code = soc.soc_code
LIMIT 100,10000

这是我正在处理的一个问题:

我看到很多类似于:

SELECT COUNT(DISTINCT p.`case`) as count
FROM FDA_CaseReports cr
  INNER JOIN ae_indi i ON i.isr = cr.isr
  LEFT JOIN ae_case_profile p ON cr.isr = p.isr

这似乎左联接可以视为内联接,是否有什么需要注意的地方?


感谢Michael清理代码,我正准备回去做这件事,点赞! - cerd
5个回答

139

有什么需要注意的吗?是的,有的——左连接是一种外连接形式,而内连接是一种内连接形式。

以下是展示差异的示例。我们将从基础数据开始:

mysql> select * from j1;
+----+------------+
| id | thing      |
+----+------------+
|  1 | hi         |
|  2 | hello      |
|  3 | guten tag  |
|  4 | ciao       |
|  5 | buongiorno |
+----+------------+

mysql> select * from j2;
+----+-----------+
| id | thing     |
+----+-----------+
|  1 | bye       |
|  3 | tschau    |
|  4 | au revoir |
|  6 | so long   |
|  7 | tschuessi |
+----+-----------+

这里我们将看到内连接和左连接之间的区别:

mysql> select * from j1 inner join j2 on j1.id = j2.id;
+----+-----------+----+-----------+
| id | thing     | id | thing     |
+----+-----------+----+-----------+
|  1 | hi        |  1 | bye       |
|  3 | guten tag |  3 | tschau    |
|  4 | ciao      |  4 | au revoir |
+----+-----------+----+-----------+
mysql> select * from j1 left join j2 on j1.id = j2.id;
+----+------------+------+-----------+
| id | thing      | id   | thing     |
+----+------------+------+-----------+
|  1 | hi         |    1 | bye       |
|  2 | hello      | NULL | NULL      |
|  3 | guten tag  |    3 | tschau    |
|  4 | ciao       |    4 | au revoir |
|  5 | buongiorno | NULL | NULL      |
+----+------------+------+-----------+

哇,5行!发生了什么?

诸如left join之类的外连接保留不匹配的行-因此,id为2和5的行由left join查询保留。其余的列将被用NULL填充。

换句话说,左连接和内连接不能互换使用。


24
左连接等外连接保留不匹配的行。这句话足以成为每所学校数据库课程中的金句。 - AbbyPaden
我一直在寻找的最佳答案。谢谢 +1 - Newbie_Android
the simpler, the better! - CodeSlave

13
内连接可以缩小返回的行集。外连接(左连接或右连接)不会改变返回的行数,只是在可能的情况下“拾取”额外的列。
在您的第一个示例中,结果将是与1_low_level_term表指定条件匹配的AECounts的行。然后对于这些行,它会尝试连接到1_pref_term1_soc_term。但是如果没有匹配,行将保持不变,并且连接的列为空。

非常感谢。可能应该补充说明,如果在非唯一键上进行连接,则外连接可以添加行,但是... - rob

7

INNER JOIN 只返回两个表中有匹配值的行,而 LEFT JOIN 返回左表中的所有行,即使右表中没有匹配的行。

下面是一个简单的例子:

TableA
ID   Value
1    TableA.Value1
2    TableA.Value2
3    TableA.Value3

TableB
ID   Value
2    TableB.ValueB
3    TableB.ValueC

内连接产生:

SELECT a.ID,a.Value,b.ID,b.Value 
FROM TableA a INNER JOIN TableB b ON b.ID = a.ID

a.ID    a.Value            b.ID    b.Value
2       TableA.Value2      2       TableB.ValueB
3       TableA.Value3      3       TableB.ValueC

左连接产生以下结果:

SELECT a.ID,a.Value,b.ID,b.Value 
FROM TableA a LEFT JOIN TableB b ON b.ID = a.ID

a.ID    a.Value            b.ID    b.Value
1       TableA.Value1      NULL    NULL
2       TableA.Value2      2       TableB.ValueB
3       TableA.Value3      3       TableB.ValueC

你可以看到,LEFT JOIN 包括了 TableA 中 ID = 1 的行,即使在 TableB 中没有匹配的 ID = 1 的行,而 INNER JOIN 排除了这一行,因为在 TableB 中没有匹配的行。
希望对你有所帮助。

5

当你想要仅返回同时满足连接条件的两个表中的结果时,请使用内连接。

当你想要返回 Table A 的所有结果,但如果 Table B 中有与 Table A 的某些记录相关的数据,则还想在同一查询中使用该数据时,请使用左连接。

当你想要返回两个表的所有结果时,请使用全连接。


1
你能否提供一些代码片段或参考资料来支持你的回答?目前听起来有点太笼统了。 - Farside

4
对于新手来说,因为当我是一名新手的时候这种方法对我很有帮助:INNER JOIN 总是 LEFT JOIN 或 RIGHT JOIN 的一个子集,所有这些联接操作总是 FULL JOIN 的子集。这帮助我理解了基本想法。

表格存储的是一系列行的集合,而不是一组行的集合,因此应该使用"子集合"而不是"子集"。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接