在数据库操作中,连接查询是一种常用的数据检索方式,它允许从两个或多个表中检索数据。本文将详细介绍SQL中的各种连接查询方式,并通过示例数据展示它们的区别和使用场景。
为了说明连接查询的概念,首先创建两个临时表,并在其中插入特定的行。这些临时表将用于演示不同类型的连接查询。
表TEMP_A包含四行数据,ID分别为1、2、3、4。表TEMP_B包含五行数据,ID分别为1、2、3、3、5。注意,表A中的第3行在表B中出现了两次,而第4行在表B中没有对应的行,同时表B中有一个孤儿行(第5行),在表A中没有对应的行。
内连接查询将返回两个表中ID字段值相同的行。使用示例数据,可以得到以下结果:
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 | Tbl A Row 1 | 1 | Tbl B Row 1 |
2 | Tbl A Row 2 | 2 | Tbl B Row 2 |
3 | Tbl A Row 3 | 3 | Tbl B Row 3a |
3 | Tbl A Row 3 | 3 | Tbl B Row 3b |
注意,表A中的第3行在表B中对应了两个不同的行,因此在结果中被重复了两次。
左连接查询不仅返回两个表中ID字段值相同的行,还会返回左表中没有在右表中找到对应行的行。使用示例数据,可以得到以下结果:
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 | Tbl A Row 1 | 1 | Tbl B Row 1 |
2 | Tbl A Row 2 | 2 | Tbl B Row 2 |
3 | Tbl A Row 3 | 3 | Tbl B Row 3a |
3 | Tbl A Row 3 | 3 | Tbl B Row 3b |
4 | Tbl A Row 4 | NULL | NULL |
注意,表A中的第4行在表B中没有对应的行,因此表B的所有字段都显示为NULL。
右连接查询与左连接查询类似,但它返回的是右表中没有在左表中找到对应行的行。使用示例数据,可以得到以下结果:
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 | Tbl A Row 1 | 1 | Tbl B Row 1 |
2 | Tbl A Row 2 | 2 | Tbl B Row 2 |
3 | Tbl A Row 3 | 3 | Tbl B Row 3a |
3 | Tbl A Row 3 | 3 | Tbl B Row 3b |
NULL | NULL | 5 | Tbl B Row 5 |
注意,表B中的第5行在表A中没有对应的行,因此表A的所有字段都显示为NULL。
全连接查询是左连接和右连接的结合,它返回两个表中ID字段值相同的行,以及左表中没有在右表中找到对应行的行和右表中没有在左表中找到对应行的行。使用示例数据,可以得到以下结果:
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 | Tbl A Row 1 | 1 | Tbl B Row 1 |
2 | Tbl A Row 2 | 2 | Tbl B Row 2 |
3 | Tbl A Row 3 | 3 | Tbl B Row 3a |
3 | Tbl A Row 3 | 3 | Tbl B Row 3b |
4 | Tbl A Row 4 | NULL | NULL |
NULL | NULL | 5 | Tbl B Row 5 |
全连接查询的结果包含了所有可能的组合,包括两个表中ID字段值相同的行,以及各自独有的行。
交叉连接查询不指定连接字段,它将返回表A中的每一行与表B中的每一行的组合。使用示例数据,可以得到以下结果:
SELECT *
FROM TEMP_A, TEMP_B;
结果如下:
Tbl_ID | Tbl_Data | Tbl_ID | Tbl_Data |
---|
交叉连接的结果数量将是两个表行数的乘积,因此会产生大量的数据。
在本例中,使用了具有唯一值的表A中的TBL_ID字段进行连接。如果连接键在两个表中都不是唯一的,那么非唯一键将导致交叉连接。让向表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 | Tbl A Row 1 | 1 | Tbl B Row 1 |
2 | Tbl A Row 2 | 2 | Tbl B Row 2 |
3 | Tbl A Row 3 | 3 | Tbl B Row 3a |
3 | Tbl A Row 3 | 3 | Tbl B Row 3b |
3 | Tbl A Row 3 dup | 3 | Tbl B Row 3a |
3 | Tbl A Row 3 dup | 3 | Tbl B Row 3b |
可以看到,由于表A中的TBL_ID字段现在不是唯一的,得到了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 | Tbl A Row 4 | NULL | NULL |
通过这种方式,可以得到表A中没有在表B中找到对应行的所有行。
CREATE TABLE TEMP_A (
Tbl_ID INT NOT NULL,
Tbl_Data VARCHAR(50) NOT NULL
);
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 TABLE TEMP_B (
Tbl_ID INT NOT NULL,
Tbl_Data VARCHAR(50) NOT NULL
);
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');