INNER JOIN 和 LEFT SEMI JOIN 的区别
Posted
技术标签:
【中文标题】INNER JOIN 和 LEFT SEMI JOIN 的区别【英文标题】:Difference between INNER JOIN and LEFT SEMI JOIN 【发布时间】:2014-03-11 10:03:26 【问题描述】:INNER JOIN
和 LEFT SEMI JOIN
有什么区别?
在下面的场景中,为什么我会得到两个不同的结果?
INNER JOIN
结果集要大得多。有人可以解释吗?我正在尝试获取仅出现在 table_2
中的 table_1
中的名称。
SELECT name
FROM table_1 a
INNER JOIN table_2 b ON a.name=b.name
SELECT name
FROM table_1 a
LEFT SEMI JOIN table_2 b ON (a.name=b.name)
【问题讨论】:
内连接将实现您的目标。在看到这个问题之前,我从未听说过半联接。left semi join
应该返回比inner join
更多的行。
inner join
仅在两个表之间存在匹配时才会返回数据。无论是否在第二个表中找到匹配记录,left join
都会从第一个表返回数据。
@GordonLinoff 不一定,LEFT SEMI JOIN
只会从左边返回一行,即使右边有多个匹配项。如果右侧有多个匹配,INNER JOIN
将返回多行。
@j03z 这不正确。如果左半连接的目的是 1)只返回左表中的信息(正如其他人所说)和 2)无论匹配如何都从左表返回行(正如我认为你所说的那样),那么那就是只是原来的左表——不需要连接来完成它。我认为其他人必须是正确的,即左半连接 1) 仅返回左表中的列,2) 仅返回在右表中匹配的行,以及 3) 将从左侧返回单行或更多匹配项。
【参考方案1】:
INNER JOIN
可以从两个表的列中返回数据,并且可以在任一侧具有多个匹配项的重复记录值。 LEFT SEMI JOIN
只能返回左侧表中的列,并从左侧表中产生一条记录,其中右侧表中有一个或多个匹配项(无论匹配项的数量如何)。它相当于(在标准 SQL 中):
SELECT name
FROM table_1 a
WHERE EXISTS(
SELECT * FROM table_2 b WHERE (a.name=b.name))
如果右侧列中有 多个 匹配行,INNER JOIN
将为右侧表中的每个匹配返回一行,而 LEFT SEMI JOIN
仅返回来自左表,无论右侧匹配的行数如何。这就是您在结果中看到不同数量的行的原因。
我正在尝试获取 table_1 中仅出现在 table_2 中的名称。
那么LEFT SEMI JOIN
是合适的查询。
【讨论】:
真的有LEFT SEMI JOIN
这样的东西吗?不只是一个SEMI JOIN
吗? RIGHT SEMI JOIN
没有意义,是吗?
在Hive,是的。
很好的答案正是我想要的。我会更准确地说出答案:“...INNER JOIN 将为每个匹配的右表行返回一行,而 LEFT SEMI JOIN...
与此相反的是LEFT ANTI JOIN,它根据一个key在左表中过滤掉右表中的数据。我想我会把这个金块留给可能正在寻找的人!【参考方案2】:
假设有 2 个表 TableA 和 TableB,只有 2 列(Id、Data)和以下数据:
表A:
+----+---------+
| Id | Data |
+----+---------+
| 1 | DataA11 |
| 1 | DataA12 |
| 1 | DataA13 |
| 2 | DataA21 |
| 3 | DataA31 |
+----+---------+
表B:
+----+---------+
| Id | Data |
+----+---------+
| 1 | DataB11 |
| 2 | DataB21 |
| 2 | DataB22 |
| 2 | DataB23 |
| 4 | DataB41 |
+----+---------+
Inner Join 列 Id
将返回两个表中的列,并且只返回匹配的记录:
.----.---------.----.---------.
| Id | Data | Id | Data |
:----+---------+----+---------:
| 1 | DataA11 | 1 | DataB11 |
:----+---------+----+---------:
| 1 | DataA12 | 1 | DataB11 |
:----+---------+----+---------:
| 1 | DataA13 | 1 | DataB11 |
:----+---------+----+---------:
| 2 | DataA21 | 2 | DataB21 |
:----+---------+----+---------:
| 2 | DataA21 | 2 | DataB22 |
:----+---------+----+---------:
| 2 | DataA21 | 2 | DataB23 |
'----'---------'----'---------'
列Id
上的左连接(或左外连接)将返回表中的列以及与左表中的记录匹配的记录(右表中的空值):
.----.---------.----.---------.
| Id | Data | Id | Data |
:----+---------+----+---------:
| 1 | DataA11 | 1 | DataB11 |
:----+---------+----+---------:
| 1 | DataA12 | 1 | DataB11 |
:----+---------+----+---------:
| 1 | DataA13 | 1 | DataB11 |
:----+---------+----+---------:
| 2 | DataA21 | 2 | DataB21 |
:----+---------+----+---------:
| 2 | DataA21 | 2 | DataB22 |
:----+---------+----+---------:
| 2 | DataA21 | 2 | DataB23 |
:----+---------+----+---------:
| 3 | DataA31 | | |
'----'---------'----'---------'
列Id
上的右连接(或右外连接)将返回表中的列以及与右表中的记录匹配的记录(左表中的空值):
┌────┬─────────┬────┬─────────┐
│ Id │ Data │ Id │ Data │
├────┼─────────┼────┼─────────┤
│ 1 │ DataA11 │ 1 │ DataB11 │
│ 1 │ DataA12 │ 1 │ DataB11 │
│ 1 │ DataA13 │ 1 │ DataB11 │
│ 2 │ DataA21 │ 2 │ DataB21 │
│ 2 │ DataA21 │ 2 │ DataB22 │
│ 2 │ DataA21 │ 2 │ DataB23 │
│ │ │ 4 │ DataB41 │
└────┴─────────┴────┴─────────┘
列Id
上的完全外连接 将返回表中的列以及与左表中的记录(右表中的空值)和右表中的记录(左表中的空值)匹配的记录表):
╔════╦═════════╦════╦═════════╗
║ Id ║ Data ║ Id ║ Data ║
╠════╬═════════╬════╬═════════╣
║ - ║ ║ ║ ║
║ 1 ║ DataA11 ║ 1 ║ DataB11 ║
║ 1 ║ DataA12 ║ 1 ║ DataB11 ║
║ 1 ║ DataA13 ║ 1 ║ DataB11 ║
║ 2 ║ DataA21 ║ 2 ║ DataB21 ║
║ 2 ║ DataA21 ║ 2 ║ DataB22 ║
║ 2 ║ DataA21 ║ 2 ║ DataB23 ║
║ 3 ║ DataA31 ║ ║ ║
║ ║ ║ 4 ║ DataB41 ║
╚════╩═════════╩════╩═════════╝
Left Semi Join Id
列将仅返回左表中的列,仅返回左表中的匹配记录:
┌────┬─────────┐
│ Id │ Data │
├────┼─────────┤
│ 1 │ DataA11 │
│ 1 │ DataA12 │
│ 1 │ DataA13 │
│ 2 │ DataA21 │
└────┴─────────┘
【讨论】:
我以前称之为“LEFT INNER Join”。 DISTINCT of A.* from INNER JOIN 结果等价于 LEFT SEMI JOIN。 Distinct 听起来不安全,假设 A 包含两条相同的记录。 即使结果最终相同,与 EXISTS 相比,使用 DISTINCT 的计划成本可能更高【参考方案3】:在 Hive 中尝试并得到以下输出
表1
1,wqe,钦奈,印度
2,斯图,塞勒姆,印度
3,米娅,班加罗尔,印度
4,yepie,纽约,美国
表2
1,wqe,钦奈,印度
2,斯图,塞勒姆,印度
3,米娅,班加罗尔,印度
5,chapie,洛杉矶,美国
内联
SELECT * FROM table1 INNER JOIN table2 ON (table1.id = table2.id);
1 wqe 印度钦奈 1 wqe 钦奈印度
2 斯图塞勒姆印度 2 斯图塞勒姆印度
3 mia 印度班加罗尔 3 mia 印度班加罗尔
左连接
SELECT * FROM table1 LEFT JOIN table2 ON (table1.id = table2.id);
1 wqe 印度钦奈 1 wqe 钦奈印度
2 斯图塞勒姆印度 2 斯图塞勒姆印度
3 mia 印度班加罗尔 3 mia 印度班加罗尔
4 yepie newyork USA NULL NULL NULL NULL
左半连接
SELECT * FROM table1 LEFT SEMI JOIN table2 ON (table1.id = table2.id);
1 wqe 印度钦奈
2 斯图塞勒姆印度
3 mia 印度班加罗尔
注意:只显示左表中的记录,而左连接显示两个表记录
【讨论】:
【参考方案4】:以上所有答案都是正确的。然而在实践中,在想象 LEFT SEMI JOIN 时,关联filter
的心智模型会有所帮助。
答案是 LEFT 表中的行子集,它们在 RIGHT TABLE 中有匹配项。
【讨论】:
以上是关于INNER JOIN 和 LEFT SEMI JOIN 的区别的主要内容,如果未能解决你的问题,请参考以下文章
SQL中left join on 、right join on、inner join on之间的区别
求助,left join union right join一直报错
R语言dplyr包进行dataframe的连接(inner_joinleft_joinright_joinfull_joinsemi_joinanti_join)操作实战