SQL多表Join时如何排除重复行 正确匹配工厂与物料提前期
问题根因
你当前的关联逻辑没有区分专属提前期和通用提前期的优先级:直接关联plant为空的通用规则行时,会把已经配置了专属提前期的工厂也匹配到通用规则,最终生成重复记录、提前期取值错误。
正确实现方案
实现核心是保证规则优先级:指定工厂的专属提前期优先级 > 空plant的通用提前期,已经匹配到专属规则的工厂不再匹配通用规则。
通用SQL写法(兼容所有SQL方言)
用CTE拆分两类规则,分别关联后合并结果,兼容性最好:
WITH specific_rule AS ( -- 提取所有配置了专属提前期的记录 SELECT porg, matnr, plant, lead_time FROM TableA WHERE plant <> '' ), general_rule AS ( -- 提取所有采购组织+物料维度的通用提前期记录 SELECT porg, matnr, lead_time FROM TableA WHERE plant = '' OR plant IS NULL ) -- 第一部分:匹配专属提前期的工厂 SELECT b.porg, sr.matnr, b.plant, sr.lead_time FROM TableB b INNER JOIN specific_rule sr ON b.porg = sr.porg AND b.plant = sr.plant UNION ALL -- 第二部分:匹配无专属规则、使用通用提前期的工厂 SELECT b.porg, gr.matnr, b.plant, gr.lead_time FROM TableB b INNER JOIN general_rule gr ON b.porg = gr.porg -- 排除已经配置了专属提前期的工厂,避免重复 LEFT JOIN specific_rule sr ON b.porg = sr.porg AND b.plant = sr.plant AND gr.matnr = sr.matnr WHERE sr.porg IS NULL ORDER BY porg, matnr, plant;
执行后输出结果和你预期完全一致。
简洁写法(支持QUALIFY语法的SQL环境)
如果使用Snowflake、BigQuery、PostgreSQL 13+等支持QUALIFY窗口函数语法的环境,可以用更短的代码实现相同逻辑:
SELECT b.porg, a.matnr, b.plant, a.lead_time FROM TableB b LEFT JOIN TableA a ON b.porg = a.porg AND (a.plant = b.plant OR a.plant = '' OR a.plant IS NULL) -- 同维度下优先取专属提前期的记录 QUALIFY ROW_NUMBER() OVER ( PARTITION BY b.porg, b.plant, a.matnr ORDER BY CASE WHEN a.plant = b.plant THEN 0 ELSE 1 END ) = 1 ORDER BY porg, matnr, plant;
逻辑说明
- 专属规则永远优先匹配:只要TableA中给对应porg+matnr+plant配置了明确的提前期,就不会再取通用值
- 通用规则仅对没有配置专属提前期的工厂生效,不会产生重复记录
- 完全匹配业务规则:空plant的提前期自动覆盖该采购组织下所有未单独配置的合法工厂
内容的提问来源于stack exchange,提问作者Tim Hellegers
相关产品推荐
相关产品推荐

