SQL LEFT JOIN 数据去重复
2020-11-05 05:15:38.0
实例:查询当前用户参与过的流程实例(instance)
关系:每个实例 (instance)对应多个任务(task),task关联办理人(userId)
select inst.*
from instance inst
left join task t on inst.id = t.inst_id
where t.user_id = #{userId}
这样查询后,如果一个人办理同一个流程中的多个任务,则会重复查出相同的instance。
其实 join 关键词查询“一对多”关系的数据,查询之后的结果的记录数,是和“ 多端 ”保持一致的,也就是“一端”的数据会重复。
left join、right join 只是选择保留下左/右端不符合join条件的多余数据,与数据重复问题无关,inner join 、outter join 也是。 所以数据的数据去重复,无法通过这几个关键词解决。
实例分析解决
有用户与角色的“一对多”,left join查询如下:
-- LEFT JOIN 查询一对多的关系,“一端”会重复
SELECT
u.id,
u.mc,
u.nl,
u.lxfs,
u.bzsm,
r.id roleId,
r.jsmc,
r.sm
FROM
test_user u
LEFT JOIN test_role r ON u.id = r.user_id
解决方法一: 结果使用group by 去重
将查询结果作为中间表,使用group by 进行去重:
-- 关联查询出结果,再使用group by 去重
select tmp.* from (
SELECT
u.id,
u.mc,
u.nl,
u.lxfs,
u.bzsm,
r.id roleId,
r.jsmc,
r.sm
FROM
test_user u
LEFT JOIN test_role r ON u.id = r.user_id
) tmp group by tmp.id;
解决方法二: “多端”使用group by 去重
去重“多端”的数据(中间表变成一对一),再关联。分析重复的原因,就是就是有多个角色对应同一个user_id,所以,将角色去重,变成“一对一”关系,再关联查询。
-- 去重“多端”的数据(中间表变成一对一),再关联
SELECT
u.id,
u.mc,
u.nl,
u.lxfs,
u.bzsm,
tmp_r.id roleId,
tmp_r.jsmc,
tmp_r.sm
FROM
test_user u
LEFT JOIN (
select r.* from test_role r group by r.user_id
) tmp_r ON u.id = tmp_r.user_id
解决方法三:使用 EXISTS
上述两种方法,其实对“多端”保留哪条数据是没有要求的(除非自己再重新定义test_role的去重方法),所以,与exists的查询效果相同。
尤其在开篇的实例中,“ 查询当前用户参与过的流程实例(instance) ”,即与参与哪个task无关时,使用exists更符合业务逻辑。
-- exists
SELECT u.*
FROM
test_user u
WHERE EXISTS (
select * from test_role r where r.user_id = u.id
);
2020-11-05 05:15:38.0