INNER JOIN和LEFT SEMI JOIN之间的区别



INNER JOINLEFT 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中具有匹配项。

LeftRight半联接,可为您提供如果使用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 

除非发生两件事,否则它们完全相同:

  1. 结果表中存在重复记录

在这种情况下,inner join会带来重复项,但left semi不会。因此inner join中所有行的distinct=left semi

  1. 您想要访问右表字段名

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"操作。

如果这两种情况不会发生在你的内心连接中,那么它们是完全相同的。因此,这取决于你如何测试它。因此会产生混乱。这个问题的一个简单答案是

其中一个不是加入

最新更新