何时使用 LEFT JOIN 以及何时使用 INNER JOIN?

Posted

技术标签:

【中文标题】何时使用 LEFT JOIN 以及何时使用 INNER JOIN?【英文标题】:When to use LEFT JOIN and when to use INNER JOIN? 【发布时间】:2012-04-05 13:58:30 【问题描述】:

我觉得我总是被教导使用LEFT JOINs,我经常看到它们与INNERs 混合使用,以在几段应该在不同页面上执行相同操作的代码中完成相同类型的查询.如下:

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

这似乎是 LEFT 也可能是 INNER 有什么问题吗?

【问题讨论】:

感谢 michael 的代码清理,刚刚回到那个,+1 【参考方案1】:

有什么问题吗?是的——左连接是外连接的一种形式,而内连接是内连接的一种形式。

以下示例显示了差异。我们将从基础数据开始:

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 |
+----+-----------+----+-----------+

嗯,3 行。

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 的行。其余列用 NULL 填充。

换句话说,左连接和内连接是不可互换的。

【讨论】:

“左连接等外连接保留不匹配的行”这条评论ALONE需要在每所学校的每门数据库课程中使用。 我一直在寻找的最佳答案。谢谢+1 越简单越好!【参考方案2】:

这是一个粗略的答案,这就是我对连接的看法。由于上述数学问题,希望这比非常精确的答案更有帮助...... ;-)

内连接缩小了返回的行集。外连接(左或右)不会改变返回的行数,但如果可能的话只是“拾取”额外的列。

在您的第一个示例中,结果将是来自AECounts 的符合1_low_level_term 表中指定条件的行。然后对于这些行,它尝试加入1_pref_term1_soc_term。但如果没有匹配项,则保留行并且加入的列为空。

【讨论】:

非常感谢。可能应该补充一点,如果在非唯一键上连接,外部连接可以添加行,但是...【参考方案3】:

INNER JOIN 只会返回两个表中存在匹配值的行,而 LEFT JOIN 将返回 LEFT 表中的所有行,即使 RIGHT 表中没有匹配的行

一个简单的例子

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

TableB
ID   Value
2    TableB.ValueB
3    TableB.ValueC

INNER JOIN 产生:

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 中没有匹配的行

HTH

【讨论】:

【参考方案4】:

如果您只想要两个表中都出现的与联接条件匹配的结果,请使用内部联接。

当您想要表 A 的所有结果时使用左连接,但如果表 B 包含与表 A 的某些记录相关的数据,那么您还希望在同一查询中使用该数据。

如果您想要两个表中的所有结果,请使用完全联接。

【讨论】:

你能用一些代码 sn-ps 或参考来支持你的答案吗?现在听起来有点太笼统了..【参考方案5】:

对于新手来说,因为它在我小时候帮助过我:INNER JOIN 始终是 LEFT 或 RIGHT JOIN 的子集,而所有这些始终是 FULL JOIN 的子集。它帮助我理解了基本思想。

【讨论】:

以上是关于何时使用 LEFT JOIN 以及何时使用 INNER JOIN?的主要内容,如果未能解决你的问题,请参考以下文章

Spark数据集何时使用Except vs Left Anti Join

OUTER APPLY 和 OUTER JOIN 有啥区别,何时使用它们? [关闭]

何时在 MySQL 中使用 STRAIGHT_JOIN

何时在包含 JOIN 和聚合的 SQL 查询中使用 *?

何时以及如何直观地隐藏内容

Thread.join 和 Synchronized 有啥区别?