执行三表LEFT JOIN查询出现重复记录,如何调整SQL获取预期结果
问题原因
你遇到的9条重复记录是一对多关联产生的笛卡尔积导致的:
- employee与coffee_shop通过shop_id关联时,两者是一对一/多对一关系,单条员工记录只会匹配到唯一的门店记录,因此两表关联返回3条结果符合预期。
- 当你额外关联coffee表时,同一个shop_id对应了3条coffee记录,单条员工+门店的组合会匹配到同门店下的所有3条咖啡记录,3*3=9就是你当前拿到的结果。
解决方案
根据你期望返回3条记录的需求,提供两种常用实现方案:
方案1:聚合同门店的咖啡信息
如果需要保留同门店的所有咖啡信息,可以用聚合函数将多条咖啡数据合并为单个字段返回,适合需要展示门店所有咖啡的场景:
SELECT e.*, cs.*, -- 可按需调整聚合逻辑,比如用GROUP_CONCAT合并咖啡名称,用MAX取最高售价等 GROUP_CONCAT(DISTINCT c.coffee_name SEPARATOR '、') AS shop_coffee_list, MAX(c.price) AS max_coffee_price FROM employee e LEFT JOIN coffee_shop cs ON e.shop_id = cs.shop_id LEFT JOIN coffee c ON cs.shop_id = c.shop_id -- 按员工唯一ID分组,保证每个员工只返回1条记录 GROUP BY e.employee_id
方案2:先对coffee表按门店去重再关联
如果你只需要每个门店匹配1条咖啡记录(比如任意一条、最新上架的、售价最高的),可以先处理coffee表,保证每个shop_id只有1条记录后再关联:
SELECT e.*, cs.*, c.* FROM employee e LEFT JOIN coffee_shop cs ON e.shop_id = cs.shop_id LEFT JOIN ( -- 子查询先按shop_id分组,保证每个门店只有1条咖啡记录 SELECT * FROM coffee GROUP BY shop_id ) c ON cs.shop_id = c.shop_id
如果使用MySQL 8.0+版本,还可以用窗口函数更灵活的筛选单条咖啡:
SELECT e.*, cs.*, c.* FROM employee e LEFT JOIN coffee_shop cs ON e.shop_id = cs.shop_id LEFT JOIN ( SELECT *, -- 按shop_id分区,按售价倒序排序取第一条,即每个门店最贵的咖啡 ROW_NUMBER() OVER(PARTITION BY shop_id ORDER BY price DESC) AS rn FROM coffee ) c ON cs.shop_id = c.shop_id AND c.rn = 1
内容的提问来源于stack exchange,提问作者WHOATEMYNOODLES
相关产品推荐
相关产品推荐

