在SQL的各类连接操作中,全连接(FULL JOIN)是返回结果最全面的一种连接方式,它会返回左表和右表中所有的记录,不管这些记录在另一张表中是否有匹配项。如果某条记录在另一张表中没有匹配,那么对应字段会显示为NULL。不过很多刚接触SQL的用户会发现,自己常用的数据库比如MySQL并没有直接支持FULL JOIN语法,这时候就需要通过其他方式来实现全连接的效果。接下来我们就一步步拆解全连接的实现方法,再分享实用技巧。

一、SQL全连接的基础概念
要理解全连接,首先得先明确它的结果集规则:假设我们有左表A和右表B,执行全连接之后,结果集会包含三部分数据:第一部分是A和B中能匹配上的记录,也就是两个表连接字段值相等的行;第二部分是A表中有但B表中没有匹配的记录,这部分B表的字段全部为NULL;第三部分是B表中有但A表中没有匹配的记录,这部分A表的字段全部为NULL。
我们可以用一个简单的例子来理解,假设现在有学生表student和成绩表score,student表存所有学生的信息,score表存部分学生的考试成绩,两个表通过student_id字段关联。如果用全连接查询两个表的数据,结果会包含所有学生(不管有没有成绩)和所有成绩记录(不管有没有对应的学生信息),没有匹配的部分字段就显示NULL。
二、不同数据库下SQL全连接的实现方法
1. 直接支持FULL JOIN的数据库(如PostgreSQL、SQL Server、Oracle)
这类数据库原生支持FULL JOIN语法,使用方式和左连接、右连接类似,直接在查询中写FULL JOIN即可,还可以结合ON指定连接条件,或者加WHERE过滤结果。
还是用上面的学生表和成绩表举例,表结构如下:
-- 学生表结构
CREATE TABLE student (
student_id INT PRIMARY KEY,
student_name VARCHAR(50),
age INT
);
-- 成绩表结构
CREATE TABLE score (
score_id INT PRIMARY KEY,
student_id INT,
subject VARCHAR(50),
score INT
);
-- 插入测试数据
INSERT INTO student VALUES (1, '张三', 18), (2, '李四', 19), (3, '王五', 18);
INSERT INTO score VALUES (1, 80, '数学', 90), (2, 85, '语文', 88), (4, 90, '英语', 95);如果要在PostgreSQL中查询全连接结果,直接执行下面的语句即可:
SELECT
s.student_id AS s_student_id,
s.student_name,
s.age,
sc.score_id,
sc.subject,
sc.score
FROM student s
FULL JOIN score sc ON s.student_id = sc.student_id;执行之后结果会包含3个学生记录和3个成绩记录,其中学生王五没有成绩,所以成绩相关字段为NULL;成绩ID为4的记录没有对应的学生信息,所以学生相关字段为NULL。
2. MySQL等不支持FULL JOIN的数据库实现方法
MySQL目前没有直接支持FULL JOIN的语法,但是我们可以通过左连接和右连接的结果取并集的方式来实现全连接的效果,也就是用LEFT JOIN查询一次,再用RIGHT JOIN查询一次,最后用UNION把两个结果合并起来。
需要注意的是,UNION会自动去重,如果两个结果中有重复的记录,只会保留一条;如果不想去重可以用UNION ALL,但全连接的场景下左连接和右连接的结果本身不会有重复,所以用UNION或者UNION ALL效果一致。
同样用上面的学生表和成绩表,MySQL中实现全连接的语句如下:
SELECT
s.student_id AS s_student_id,
s.student_name,
s.age,
sc.score_id,
sc.subject,
sc.score
FROM student s
LEFT JOIN score sc ON s.student_id = sc.student_id
UNION
SELECT
s.student_id AS s_student_id,
s.student_name,
s.age,
sc.score_id,
sc.subject,
sc.score
FROM student s
RIGHT JOIN score sc ON s.student_id = sc.student_id;这段语句的执行逻辑是:首先左连接查询所有学生及其对应的成绩,没有成绩的学生也会显示;然后右连接查询所有成绩及其对应的学生,没有对应学生的成绩也会显示;最后把两个结果合并,就得到了和FULL JOIN一样的结果集。
三、SQL全连接的3个使用技巧
技巧1:过滤全连接中的NULL值,按需筛选数据
全连接会返回所有记录,包括不匹配的NULL值记录,实际使用中我们往往只需要其中一部分数据,这时候可以在查询中加上WHERE条件过滤NULL值。
比如我们只想查询有成绩但是没有学生信息的异常成绩记录,就可以在全连接之后过滤学生ID为NULL的记录:
SELECT
s.student_id AS s_student_id,
s.student_name,
s.age,
sc.score_id,
sc.subject,
sc.score
FROM student s
FULL JOIN score sc ON s.student_id = sc.student_id
WHERE s.student_id IS NULL;如果是用MySQL的左连接+右连接+UNION的方式实现,也可以在合并之后再加过滤条件,或者用子查询把合并结果作为临时表再过滤:
SELECT * FROM (
SELECT
s.student_id AS s_student_id,
s.student_name,
s.age,
sc.score_id,
sc.subject,
sc.score
FROM student s
LEFT JOIN score sc ON s.student_id = sc.student_id
UNION
SELECT
s.student_id AS s_student_id,
s.student_name,
s.age,
sc.score_id,
sc.subject,
sc.score
FROM student s
RIGHT JOIN score sc ON s.student_id = sc.student_id
) t
WHERE t.s_student_id IS NULL;这样就能直接拿到所有没有对应学生信息的成绩记录,方便排查数据异常。
技巧2:给连接字段取统一别名,避免结果集字段混乱
全连接的两个表往往有同名的连接字段,比如上面的两个表都有student_id字段,如果不处理的话结果集会有两个同名的student_id列,不仅看起来混乱,后续程序处理也容易出错。这时候我们可以给两个表的连接字段取不同的别名,或者在查询的时候明确指定要返回的字段,避免重名。
比如我们可以把左表的student_id命名为left_student_id,右表的命名为right_student_id,这样结果集的字段就清晰了:
SELECT
s.student_id AS left_student_id,
s.student_name,
s.age,
sc.student_id AS right_student_id,
sc.score_id,
sc.subject,
sc.score
FROM student s
FULL JOIN score sc ON s.student_id = sc.student_id;如果是用UNION方式实现的话,要注意两个SELECT语句返回的字段数量和类型必须一致,所以别名的规则也要统一,不然UNION会执行失败。
技巧3:结合COALESCE函数处理NULL值,提升结果可读性
全连接结果中不匹配的字段会显示为NULL,有时候NULL值不够直观,我们可以用COALESCE函数把NULL值替换成我们想要的提示文本,让结果更易读。
COALESCE函数的作用是返回参数列表中第一个非NULL的值,如果所有参数都是NULL,就返回NULL。比如我们可以把学生姓名中的NULL替换成“无对应学生”,科目中的NULL替换成“无成绩记录”:
SELECT
COALESCE(s.student_id, sc.student_id) AS student_id,
COALESCE(s.student_name, '无对应学生') AS student_name,
s.age,
sc.score_id,
COALESCE(sc.subject, '无成绩记录') AS subject,
sc.score
FROM student s
FULL JOIN score sc ON s.student_id = sc.student_id;这样查询结果中,没有学生信息的成绩记录,学生姓名会显示“无对应学生”;没有成绩的学生记录,科目会显示“无成绩记录”,比直接显示NULL要清晰很多,也方便后续的数据统计和展示。
四、全连接的使用注意事项
首先要注意数据库的支持情况,不要在不支持FULL JOIN的数据库中直接写FULL JOIN语法,不然会报语法错误,这种情况记得用左连接+右连接+UNION的方式实现。
其次要注意连接条件的正确性,全连接的连接条件和内连接、左连接一样,需要明确指定两个表的关联字段,如果连接条件写错,会导致结果集出现笛卡尔积,数据量爆炸,查询效率极低。
最后要注意性能问题,全连接会返回两个表的所有记录,如果两张表的数据量都很大,全连接的结果集会非常庞大,查询速度会很慢,这时候最好先过滤数据,再执行全连接,或者考虑是否真的需要全量数据,避免不必要的性能消耗。