SQL LEFT JOIN 数据去重复

标签:

本文出自jvm123.com-java技术分享站:http://jvm123.com/2020/11/sql-left-join-shu.html

实例:查询当前用户参与过的流程实例(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
SQL LEFT JOIN 数据去重复插图

解决方法一: 结果使用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;
SQL LEFT JOIN 数据去重复插图(1)

解决方法二: “多端”使用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 
SQL LEFT JOIN 数据去重复插图(2)

解决方法三:使用 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
);
SQL LEFT JOIN 数据去重复插图(3)

《SQL LEFT JOIN 数据去重复》有2个笔记:

发表评论