SQL联表查询使用DISTINCT仍出现id重复的问题求解
问题根因
DISTINCT 本质是对查询返回的整行所有字段的组合值做去重,并非只针对你写在括号里的o.id字段生效——括号在这里只是普通的表达式包裹符号,不会改变DISTINCT的作用逻辑。
你的结果中重复id对应的excelID值不同,因此id + status + excelID的整行组合是唯一的,自然不会被DISTINCT过滤掉。
另外你原查询里存在两个冗余逻辑:
- 子查询中
SELECT DISTINCT(orderId) id, excelID FROM parcels的去重逻辑无效:当同一个orderId对应多个不同excelID时,DISTINCT会保留所有orderId+excelID的唯一组合,还是会返回同一个orderId的多条记录 LEFT JOIN后加WHERE p.id is not null的写法等价于直接写INNER JOIN,不需要额外做左连接再过滤空值
修改方案
要实现每个id仅返回单条记录,核心是对同一个订单关联到的多个包裹记录做分组聚合,按业务规则取其中一条excelID即可。
方案1:通用聚合写法(兼容所有SQL版本)
如果你的业务规则是取每个订单关联的最大/最小excelID,直接用GROUP BY聚合即可,写法最简单兼容性最好:
SELECT o.id, o.status, -- 如需取最小excelID替换为MIN(p.excelID)即可 MAX(p.excelID) AS excelID FROM orders AS o INNER JOIN parcels AS p ON o.id = p.orderId WHERE o.id IS NOT NULL GROUP BY o.id, o.status
方案2:窗口函数写法(支持MySQL8.0+/PostgreSQL/SQL Server等主流数据库)
如果你需要更灵活的取数规则(比如按创建时间、excelID排序取指定位置的记录),可以用窗口函数ROW_NUMBER()实现,以下写法的返回结果和你给出的预期结果完全一致:
SELECT id, status, excelID FROM ( SELECT o.id, o.status, p.excelID, ROW_NUMBER() OVER (PARTITION BY o.id ORDER BY p.excelID DESC) AS row_sort FROM orders AS o INNER JOIN parcels AS p ON o.id = p.orderId WHERE o.id IS NOT NULL ) t WHERE row_sort = 1
上述语句中PARTITION BY o.id表示按订单id分组,ORDER BY p.excelID DESC表示组内按excelID倒序排列,最后取每组排序为1的记录,就实现了每个id仅返回一条记录的需求。
内容的提问来源于stack exchange,提问作者SnakeR
相关产品推荐
相关产品推荐

