返回

巧用LEFT JOIN与GROUP BY,巧解一对多关联查询数据重复问题

后端

问题背景

在进行数据库查询时,我们经常会遇到一对多关联查询的情况,即一个表中的记录可能对应多个另一个表中的记录。在进行关联查询时,如果处理不当,可能会导致查询结果出现数据重复的问题。

LEFT JOIN与GROUP BY的使用

为了解决一对多关联查询中出现的数据重复问题,我们可以使用LEFT JOIN和GROUP BY来进行数据处理。LEFT JOIN是一种外连接,它可以将主表中的所有记录与子表中的匹配记录关联起来,即使子表中没有匹配的记录,也会在查询结果中显示主表中的记录。GROUP BY是一种分组操作,它可以将具有相同值的数据行分组在一起,并对每个组执行聚合操作,如求和、求平均值、求最大值等。

具体操作步骤

  1. 使用LEFT JOIN将主表与子表关联起来,确保主表中的所有记录都与子表中的匹配记录关联。
  2. 使用GROUP BY对关联查询的结果进行分组,将具有相同值的数据行分组在一起。
  3. 对每个组执行聚合操作,如求和、求平均值、求最大值等,以获得最终的查询结果。

示例

需求:展示列表车辆品牌信息、车主信息。

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           宝马32         宝马        3         王五
4           宝马52         宝马        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           宝马32         宝马        王五, 赵六
4           宝马52         宝马        王五, 赵六

可以看到,在使用GROUP BY对查询结果进行分组后,每辆车只对应一条记录,并且车主信息使用GROUP_CONCAT函数进行了合并。这样就可以解决一对多关联查询中出现的数据重复问题了。