65.9K
CodeProject 正在变化。 阅读更多。
Home

在 SQL 中连接表

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (27投票s)

2013 年 4 月 3 日

CPOL

6分钟阅读

viewsIcon

126995

解释不同的连接表的方法

引言

本文档将尝试解释两种表连接的工作方式。为了更好地解释这一点,我创建了两个包含特定行的临时表来证明这一点。请参阅附录 A 中的 SQL 语句来创建示例临时表。我们有一个名为 TEMP_A 的表,其中包含四行,这四行的 ID 分别是唯一的,编号为 1、2、3、4。然后我们还有一个名为 TEMP_B 的表,其中包含五行。它的行是 1、2、3、3、5。请注意,表 A 中的行 1 和 2 在表 B 中各有一个引用。

行 3 在表 B 中有两个引用,行 4 在表 B 中没有任何引用,而表 B 中有一行孤立行(行 5),在表 A 中没有父行。

另外请注意,保留字 inner 和 outer 是可选的。left outer join 和 left join 的意思完全相同。

好了,现在开始有趣的部分。

普通连接(或内部连接)

在 ID 字段上连接(或内部连接)这两个表,您将获得两个集合的交集中的所有行,这意味着它们具有相同的值。

使用附录 A 中创建的数据样本,我们将得到以下结果:

select *
from TEMP_A
INNER JOIN TEMP_B
	ON TEMP_A.Tbl_ID = TEMP_B.Tbl_ID
Tbl_ID Tbl_Data Tbl_ID Tbl_Data
1 表 A 第 1 行 1 表 B 第 1 行
2 表 A 第 2 行 2 表 B 第 2 行
3 表 A 第 3 行 3 表 B 第 3a 行
3 表 A 第 3 行 3 表 B 第 3b 行

请注意,表 A 中的第 3 行会根据表 B 中的每个对应行进行一次重复。

左连接(或左外连接)

左连接将返回两个表的交集,此外,它还将返回左表中没有对应行的行。什么是左,什么是右?嗯,左表是指定的第一个表,右表是指定的第二个表。或者右表是 Join 语句之后的表。左边是 SQL 正在处理的其余数据。

使用附录 A 中创建的数据样本,我们将得到以下结果:

select *
from TEMP_A
LEFT OUTER JOIN TEMP_B
	ON TEMP_A.Tbl_ID = TEMP_B.Tbl_ID
Tbl_ID Tbl_Data Tbl_ID Tbl_Data
1 表 A 第 1 行 1 表 B 第 1 行
2 表 A 第 2 行 2 表 B 第 2 行
3 表 A 第 3 行 3 表 B 第 3a 行
3 表 A 第 3 行 3 表 B 第 3b 行
4 表 A 第 4 行 NULL NULL

请注意,表 A 中的第 4 行现在已包含在内,但由于表 B 中没有对应的行,因此表 B 的所有字段都包含 NULL。

右连接(或右外连接)

右连接非常类似于左连接,但它返回右表中没有对应左表行的行。

使用附录 A 中创建的数据样本,我们将得到以下结果:

select *
from TEMP_A
RIGHT OUTER JOIN TEMP_B
	ON TEMP_A.Tbl_ID = TEMP_B.Tbl_ID
Tbl_ID Tbl_Data Tbl_ID Tbl_Data
1 表 A 第 1 行 1 表 B 第 1 行
2 表 A 第 2 行 2 表 B 第 2 行
3 表 A 第 3 行 3 表 B 第 3a 行
3 表 A 第 3 行 3 表 B 第 3b 行
NULL NULL 5 表 B 第 5 行

此集合也包含 5 行。但这次最后一行包含来自表 B 的数据,而来自表 A 的所有数据均为 NULL。

全连接(或全外连接)

这就像左连接和右连接的组合。它将返回两个表的交集,以及表 A 中所有没有对应表 B 行的行,以及表 B 中所有没有对应表 A 行的行。

使用附录 A 中创建的数据样本,我们将得到以下结果:

select *
from TEMP_A
FULL OUTER JOIN TEMP_B
	ON TEMP_A.Tbl_ID = TEMP_B.Tbl_ID
Tbl_ID Tbl_Data Tbl_ID Tbl_Data
1 表 A 第 1 行 1 表 B 第 1 行
2 表 A 第 2 行 2 表 B 第 2 行
3 表 A 第 3 行 3 表 B 第 3a 行
3 表 A 第 3 行 3 表 B 第 3b 行
4 表 A 第 4 行 NULL NULL
NULL NULL 5 表 B 第 5 行

交叉连接

嗯,交叉连接(Cross Join)并不是真正的连接,你不需要指定连接的字段,只需要指定表的名称。它会将表 A 中的每一行与表 B 中的每一行匹配起来,所以最终结果会有很多行。

使用附录 A 中创建的数据样本,我们将得到以下结果:

select *
from TEMP_A, TEMP_B
Tbl_ID Tbl_Data Tbl_ID Tbl_Data
1 表 A 第 1 行 1 表 B 第 1 行
1 表 A 第 1 行 2 表 B 第 2 行
1 表 A 第 1 行 3 表 B 第 3a 行
1 表 A 第 1 行 3 表 B 第 3b 行
1 表 A 第 1 行 5 表 B 第 5 行
2 表 A 第 2 行 1 表 B 第 1 行
2 表 A 第 2 行 2 表 B 第 2 行
2 表 A 第 2 行 3 表 B 第 3a 行
2 表 A 第 2 行 3 表 B 第 3b 行
2 表 A 第 2 行 5 表 B 第 5 行
3 表 A 第 3 行 1 表 B 第 1 行
3 表 A 第 3 行 2 表 B 第 2 行
3 表 A 第 3 行 3 表 B 第 3a 行
3 表 A 第 3 行 3 表 B 第 3b 行
3 表 A 第 3 行 5 表 B 第 5 行
4 表 A 第 4 行 1 表 B 第 1 行
4 表 A 第 4 行 2 表 B 第 2 行
4 表 A 第 4 行 3 表 B 第 3a 行
4 表 A 第 4 行 3 表 B 第 3b 行
4 表 A 第 4 行 5 表 B 第 5 行

为什么不使用唯一键是不好的

在本次解释中,我使用了 TBL_ID 字段具有唯一值的表 A。不建议使用连接键在两个表中的至少一个表中不唯一的表。如果是这种情况,您会发现非唯一键会执行交叉连接。让我们向表 A 添加一行来演示这一点。

insert into TEMP_A values (3, 'Tbl A Row 3 dup')

现在像以前一样选择一个普通连接,并观察结果。

select *
from TEMP_A
INNER JOIN TEMP_B
	ON TEMP_A.Tbl_ID = TEMP_B.Tbl_ID
Tbl_ID Tbl_Data Tbl_ID Tbl_Data
1 表 A 第 1 行 1 表 B 第 1 行
2 表 A 第 2 行 2 表 B 第 2 行
3 表 A 第 3 行 3 表 B 第 3a 行
3 表 A 第 3 行 3 表 B 第 3b 行
3 表 A 第 3 行(重复) 3 表 B 第 3a 行
3 表 A 第 3 行(重复) 3 表 B 第 3b 行

看看我们现在返回了 6 行。

使用连接选择孤立行

那么,如何获取一个表中所有没有对应另一个表行的行呢?很简单,使用左连接或右连接,并加上一个 WHERE 子句移除不需要的行。

使用样本数据

select *
from TEMP_A
LEFT OUTER JOIN TEMP_B
	ON TEMP_A.Tbl_ID = TEMP_B.Tbl_ID
where TEMP_B.Tbl_ID is null
Tbl_ID Tbl_Data Tbl_ID Tbl_Data
4 表 A 第 4 行 NULL NULL

附录 A(样本数据)

-- Create the first temp table
create table TEMP_A (
	Tbl_ID	int not null,
	Tbl_Data varchar(50) not null
)
-- Insert sample data in to first temp table
insert into TEMP_A values (1, 'Tbl A Row 1')
insert into TEMP_A values (2, 'Tbl A Row 2')
insert into TEMP_A values (3, 'Tbl A Row 3')
insert into TEMP_A values (4, 'Tbl A Row 4')

-- Create the second temp table
create table TEMP_B (
	Tbl_ID	int not null,
	Tbl_Data varchar(50) not null
)
-- Inset sample data into the second temp table
insert into TEMP_B values (1, 'Tbl B Row 1')
insert into TEMP_B values (2, 'Tbl B Row 2')
insert into TEMP_B values (3, 'Tbl B Row 3a')
insert into TEMP_B values (3, 'Tbl B Row 3b')
insert into TEMP_B values (5, 'Tbl B Row 5')
© . All rights reserved.