返回
巧用LEFT JOIN与GROUP BY,巧解一对多关联查询数据重复问题
后端
2023-12-06 10:55:13
问题背景
在进行数据库查询时,我们经常会遇到一对多关联查询的情况,即一个表中的记录可能对应多个另一个表中的记录。在进行关联查询时,如果处理不当,可能会导致查询结果出现数据重复的问题。
LEFT JOIN与GROUP BY的使用
为了解决一对多关联查询中出现的数据重复问题,我们可以使用LEFT JOIN和GROUP BY来进行数据处理。LEFT JOIN是一种外连接,它可以将主表中的所有记录与子表中的匹配记录关联起来,即使子表中没有匹配的记录,也会在查询结果中显示主表中的记录。GROUP BY是一种分组操作,它可以将具有相同值的数据行分组在一起,并对每个组执行聚合操作,如求和、求平均值、求最大值等。
具体操作步骤
- 使用LEFT JOIN将主表与子表关联起来,确保主表中的所有记录都与子表中的匹配记录关联。
- 使用GROUP BY对关联查询的结果进行分组,将具有相同值的数据行分组在一起。
- 对每个组执行聚合操作,如求和、求平均值、求最大值等,以获得最终的查询结果。
示例
需求:展示列表车辆品牌信息、车主信息。
SELECT
brand.brand_id,
brand.brand_name,
owner.owner_id,
owner.owner_name
FROM
brand
LEFT JOIN
owner ON brand.brand_id = owner.brand_id;
执行结果:
brand_id brand_name owner_id owner_name
1 奔驰 1 张三
1 奔驰 2 李四
2 宝马 3 王五
2 宝马 4 赵六
需求:展示列表车辆信息、车辆品牌信息、车主信息。
SELECT
vehicle.vehicle_id,
vehicle.vehicle_name,
brand.brand_id,
brand.brand_name,
owner.owner_id,
owner.owner_name
FROM
vehicle
LEFT JOIN
brand ON vehicle.brand_id = brand.brand_id
LEFT JOIN
owner ON brand.brand_id = owner.brand_id;
执行结果:
vehicle_id vehicle_name brand_id brand_name owner_id owner_name
1 奔驰A级 1 奔驰 1 张三
2 奔驰B级 1 奔驰 2 李四
3 宝马3系 2 宝马 3 王五
4 宝马5系 2 宝马 4 赵六
可以看到,在第一个需求的查询结果中,每辆车都对应一条记录,而在第二个需求的查询结果中,每辆车对应多条记录。这是因为在第二个需求中,我们关联了三个表,而主表vehicle中的每条记录都可能对应多条brand表和owner表中的记录。为了解决这个问题,我们可以使用GROUP BY对关联查询的结果进行分组,将具有相同值的数据行分组在一起。
SELECT
vehicle.vehicle_id,
vehicle.vehicle_name,
brand.brand_id,
brand.brand_name,
GROUP_CONCAT(owner.owner_name) AS owner_names
FROM
vehicle
LEFT JOIN
brand ON vehicle.brand_id = brand.brand_id
LEFT JOIN
owner ON brand.brand_id = owner.brand_id
GROUP BY
vehicle.vehicle_id,
vehicle.vehicle_name,
brand.brand_id,
brand.brand_name;
执行结果:
vehicle_id vehicle_name brand_id brand_name owner_names
1 奔驰A级 1 奔驰 张三, 李四
2 奔驰B级 1 奔驰 张三, 李四
3 宝马3系 2 宝马 王五, 赵六
4 宝马5系 2 宝马 王五, 赵六
可以看到,在使用GROUP BY对查询结果进行分组后,每辆车只对应一条记录,并且车主信息使用GROUP_CONCAT函数进行了合并。这样就可以解决一对多关联查询中出现的数据重复问题了。