mysql数据库的多表查询场景中,全连接用于返回两个表的所有记录,不管记录是否在另一个表中存在匹配项。但mysql官方并未提供原生的full join语法,因此需要借助其他查询方式实现相同的效果。
mysql全连接的核心概念
全连接也叫全外连接,它的查询结果包含三部分内容:两个表中匹配的记录、左表存在但右表不存在的记录、右表存在但左表不存在的记录。如果某一边的表没有匹配记录,对应字段会显示为null。
在标准SQL语法中,全连接的写法是full outer join,但mysql执行该语法会直接报错,这是mysql的一个特性限制,因此我们需要用其他方式模拟实现。
用union模拟full join的实现思路
union操作符可以合并两个或多个select语句的结果集,并且默认会去重。我们可以利用这个特性,把左连接和右连接的结果合并起来,就能得到全连接的效果,具体思路如下:
- 第一步:执行左连接查询,获取左表所有记录以及匹配的右表记录,右表无匹配则字段为null
- 第二步:执行右连接查询,获取右表所有记录以及匹配的左表记录,左表无匹配则字段为null
- 第三步:用union合并两个查询的结果,自动去重重复的中间匹配记录,得到完整的全连接结果
具体实现示例
1. 准备测试表和数据
首先创建两个测试表,分别是学生表和成绩表,学生表存储学生基本信息,成绩表存储学生的考试成绩,部分学生可能没有成绩记录,部分成绩记录可能对应不存在的学生(模拟脏数据场景)。
-- 创建学生表
create table student (
id int primary key auto_increment,
name varchar(50) not null,
age int
);
-- 创建成绩表
create table score (
id int primary key auto_increment,
student_id int,
subject varchar(50),
grade int
);
-- 插入学生表测试数据
insert into student (name, age) values ('张三', 18);
insert into student (name, age) values ('李四', 19);
insert into student (name, age) values ('王五', 20);
-- 插入成绩表测试数据
insert into score (student_id, subject, grade) values (1, '数学', 90);
insert into score (student_id, subject, grade) values (1, '语文', 85);
insert into score (student_id, subject, grade) values (3, '英语', 88);
insert into score (student_id, subject, grade) values (5, '物理', 92);
2. 左连接查询获取左表全量数据
先执行左连接,以学生表为左表,关联成绩表,得到所有学生的信息以及对应的成绩,没有成绩的学生成绩字段为null。
select
s.id as student_id,
s.name,
s.age,
sc.subject,
sc.grade
from student s
left join score sc on s.id = sc.student_id;
该查询的结果会包含张三、李四、王五三个学生的记录,其中李四没有成绩记录,对应的subject和grade字段为null。
3. 右连接查询获取右表全量数据
再执行右连接,同样以学生表为左表,关联成绩表,得到所有成绩记录对应的学生信息,成绩记录对应的学生不存在时,学生字段为null。
select
s.id as student_id,
s.name,
s.age,
sc.subject,
sc.grade
from student s
right join score sc on s.id = sc.student_id;
该查询的结果会包含张三、王五的成绩记录,以及student_id为5的脏成绩记录,对应的学生姓名字段为null。
4. 用union合并结果实现全连接
把上面的左连接和右连接结果用union合并,就可以得到全连接的效果,包含所有学生和所有成绩记录。
select
s.id as student_id,
s.name,
s.age,
sc.subject,
sc.grade
from student s
left join score sc on s.id = sc.student_id
union
select
s.id as student_id,
s.name,
s.age,
sc.subject,
sc.grade
from student s
right join score sc on s.id = sc.student_id;
执行上述查询后,结果会包含三个学生的所有记录,以及那条脏成绩记录,重复的张三的成绩记录会被union自动去重,最终得到完整的全连接结果。
注意事项
- 使用union时,两个select语句的字段数量必须一致,字段顺序最好也保持一致,否则结果会出现字段错位
- 如果确定两个查询不会有重复记录,可以使用union all代替union,union all不会去重,执行效率更高
- 如果需要保留重复记录,就不能使用union,要根据实际业务场景选择合适的合并方式
使用union模拟full join是mysql中实现全连接最常用的方法,只要理清左连接和右连接的返回逻辑,就能快速写出正确的查询语句。