INNER JOIN
和LEFT SEMI JOIN
之间有什么区别?
在下面的场景中,为什么我会得到两个不同的结果?
INNER JOIN
结果集要大得多。有人能解释一下吗?我正在尝试获取table_1
中仅出现在table_2
中的名称。
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)
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
仅返回左侧表中的行,而与右侧的匹配行数无关。这就是为什么您在结果中看到不同数量的行。
我正在尝试获取表_1中只出现在表_2中的名称。
则LEFT SEMI JOIN
是要使用的适当查询。
假设有两个表TableA和TableB,只有两列(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 |
+----+---------+
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
上的左联接(或左外联接)将返回两个表中的列以及与左表中的记录匹配的记录(右表中的Null值):
.----.---------.----.---------.
| 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
上的完全外部联接将返回两个表中的列以及与左表中的记录(右表中的Null值)和右表中记录(左表中为Null值)匹配的记录:
╔════╦═════════╦════╦═════════╗
║ 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 ║
╚════╩═════════╩════╩═════════╝
列Id
上的左半联接将只返回左表中的列,只返回左表格中的匹配记录:
┌────┬─────────┐
│ Id │ Data │
├────┼─────────┤
│ 1 │ DataA11 │
│ 1 │ DataA12 │
│ 1 │ DataA13 │
│ 2 │ DataA21 │
└────┴─────────┘
在Hive中尝试,得到以下输出
表1
1,wqe,印度钦奈
2,stu,salem,印度
3,米亚,班加罗尔,印度
美国纽约yepie 4号
表2
1,wqe,印度钦奈
2,stu,salem,印度
3,米亚,班加罗尔,印度
5,chapie,洛杉矶,美国
内部加入
SELECT*FROM table1 INNER JOIN table2 ON(table1.id=table2.id);
印度钦奈1个
2 stu salem india 2 stu salem india
印度3米亚邦3米亚邦
左加入
SELECT*FROM table1 LEFT JOIN table2 ON(table1.id=table2.id);
印度钦奈1个
2 stu salem india 2 stu salem india
印度3米亚邦3米亚邦
4 yepie纽约美国NULL NULL NULL
左半加入
SELECT*FROM table1 LEFT SEMI JOIN table2 ON(table1.id=table2.id);
印度钦奈
2 stu salem印度
3米亚班加罗尔印度
注意:只显示左表中的记录,而对于左联接,两个表记录都显示
以上所有答案都是正确的。然而,在实践中,当想象LEFT SEMI JOIN时,将filter
的心理模型联系起来会有所帮助。
答案是LEFT表中的行的子集,这些行在RIGHT table中具有匹配项。
将Left
与Right
半联接,可为您提供如果使用Right
联接则会保留在Left
中的行
Left table:
KEY: 1, 2, 3
VAL1: a, b, c
Right table:
KEY: 2, 3, 4
VAL2: d, e, f
# Semi join:
KEY: 2, 3
VAL1: b, c
# Actual inner join
KEY: 2, 3
VAL1: b, c
VAL2: d, e
除非发生两件事,否则它们完全相同:
- 结果表中存在重复记录
在这种情况下,inner join
会带来重复项,但left semi
不会。因此inner join
中所有行的distinct
=left semi
- 您想要访问右表字段名
在inner join
中,我们可以得到结果中的左表和右表。但有了left semi
,你只能得到左边的桌子。为什么?检查此查询:
SELECT name
FROM table_left left
WHERE EXISTS(
SELECT * FROM table_right right WHERE (left.name=right.name))
在这个查询中,我们无法访问内部表(table_right)中的字段。这就是left semi
在幕后的实现方式。这是一个"is in"操作。
如果这两种情况不会发生在你的内心连接中,那么它们是完全相同的。因此,这取决于你如何测试它。因此会产生混乱。这个问题的一个简单答案是
其中一个不是加入