说明:本文介绍数据库表关联查询,left join 使用的坑,以 MySQL 为例,假设有以下两张表,学生表、班级表
(学生表)
(班级表)
场景一:逻辑删除
如下,分页查询学生列表信息,并关联查询学生的班级信息,为了过滤掉逻辑删除的记录,给每张表都加上了 deleted = false 条件
-- 分页查询学生列表(方式一)
select t1.id, t1.name, t2.class_name, t2.teacher_name
from tb_student t1
left join tb_class t2 on t1.class_id = t2.id
where t1.deleted = false
and t2.deleted = false
limit 0, 100
执行,发现没有关联到班级的学生记录没有查出来
原因在于 t2.deleted = false 条件,没有关联到班级的学生记录,没有这个字段,自然会被过滤掉。但又不能直接去掉该条件,不然就有脏数据。
可修改 SQL 如下,将逻辑删除条件加到关联上
-- 分页查询学生列表(方式二)
select t1.id, t1.name, t2.class_name, t2.teacher_name
from tb_student t1
left join tb_class t2 on t1.class_id = t2.id and t2.deleted = false
where t1.deleted = false
limit 0, 100
这就能查出来了
场景二:主表关联子表
新增一张表,专门用来存学生的联系人信息,如下:
添加几条数据
查询学生信息
-- 查询学生信息
select t1.id, t1.student_no, t1.name, t2.contact_person_name, t2.contact_person_phone
from tb_student t1
left join tb_student_contact_info t2 on t1.student_no = t2.student_no and t2.deleted = false
where t1.deleted = false
limit 0, 100
可以看到,因为学生表与联系人表是 一对多 的关系,所以做关联查询的时候,学生记录有重复
要避免这种情况,有两个办法,要么在代码里封装,学生对象里封装一个联系人集合,这样能保证学生记录是单条;要么不返回联系人字段,用学生信息 group by,如下:
select t1.id, t1.student_no, t1.name
from tb_student t1
left join tb_student_contact_info t2 on t1.student_no = t2.student_no and t2.deleted = false
where t1.deleted = false
group by t1.id, t1.student_no, t1.name
limit 0, 100;
这样不会出现重复的学生记录。既保留了联系人表 t2 的查询条件(如果要对 t2 表加筛选条件),又保证了查询结果是以学生维度展示的。
总结
本文介绍了数据库表关联查询值得注意的两个点