多对多关联场景下SQL查询如何避免返回重复记录
JOIN结果行数异常排查与优化方案
核心原因
结果行数远大于事故表原始行数的核心原因是Rentals表中同一个关联键(customer_id/姓名)存在多条记录,1条事故表数据会匹配到同一个客户的N条租赁记录,最终总数据量被放大到1500的数十倍。
排查步骤
- 先确认Rentals表的重复情况,执行查询:
SELECT customer_id, COUNT(*) AS rental_count FROM rentals GROUP BY customer_id HAVING COUNT(*) > 1 ORDER BY rental_count DESC
返回结果中的条目就是存在多条租赁记录的客户,可直接验证行数放大的原因。 - 明确业务关联逻辑:你需要的是事故发生时对应的那条租赁记录?还是客户的最新静态属性?还是该客户所有租赁记录的关联结果?不同需求对应完全不同的关联写法。
通用优化方案
场景1:仅需要客户静态属性(出生日期、是否封禁等不随租赁单变化的字段)
先对Rentals表按关联键去重后再关联,避免多匹配:
SELECT a.*, r.market, r.date_of_birth, r.is_blocked, r.rate_type FROM `accidents` a LEFT JOIN ( SELECT DISTINCT customer_id, market, date_of_birth, is_blocked, rate_type FROM `rentals` ) r USING (customer_id) ORDER BY accident_dt DESC
场景2:需要关联事故发生时对应的租赁记录
补充时间匹配条件,限定仅匹配事故发生时段内的租赁单:
SELECT a.*, r.market, r.date_of_birth, r.is_blocked, r.rate_type FROM `accidents` a LEFT JOIN `rentals` r ON a.customer_id = r.customer_id -- 请根据实际表字段调整时间范围判断逻辑 AND a.accident_dt BETWEEN r.rental_start_dt AND r.rental_end_dt ORDER BY accident_dt DESC
场景3:仅需要客户最新一条租赁记录的属性
用窗口函数提前过滤出每个客户的最新租赁记录再关联:
SELECT a.*, r.market, r.date_of_birth, r.is_blocked, r.rate_type FROM `accidents` a LEFT JOIN ( SELECT *, ROW_NUMBER() OVER(PARTITION BY customer_id ORDER BY rental_create_dt DESC) AS rn FROM `rentals` ) r ON a.customer_id = r.customer_id AND r.rn = 1 ORDER BY accident_dt DESC
内容的提问来源于stack exchange,提问作者lillemongrab
相关产品推荐
相关产品推荐

