合并含空值行并保留唯一组合的SQL解决方案咨询
我明白你的痛点了——想用窗口函数按组取最大值来合并行,但空值打乱了分区逻辑,导致没法得到想要的唯一组合。先看看你的原查询问题出在哪:
SELECT SALES_ORG ,MAX(MATERIAL) OVER (PARTITION BY SALES_ORG,MATERIAL ORDER BY MATERIAL) as MATERIAL ,MAX(MGROUP) OVER (PARTITION BY SALES_ORG,MATERIAL,MGROUP ORDER BY MGROUP ) as MGROUP ,MAX(SERVICE) OVER (PARTITION BY SALES_ORG,MATERIAL,MGROUP,SERVICE ORDER BY SERVICE ) as SERVICE FROM SALES
你把所有字段都塞进了PARTITION BY里,这意味着只有当所有字段完全一致(包括空值的位置)时,行才会被分到同一分区。空值的行自然会被单独划分,MAX函数根本没机会合并它们。
下面给你几个实用的解决思路:
方案1:GROUP BY核心唯一键 + 聚合函数(最推荐)
如果你的唯一组合是基于SALES_ORG和MATERIAL(这两个字段能确定一组唯一数据),直接按这两个字段分组,对其他字段用MAX提取非空值就行——MAX会自动忽略空值,只返回分组内的有效非空值:
SELECT SALES_ORG, MATERIAL, MAX(MGROUP) AS MGROUP, MAX(SERVICE) AS SERVICE FROM SALES GROUP BY SALES_ORG, MATERIAL
举个例子:如果同一SALES_ORG+MATERIAL下有两行,一行MGROUP为空、SERVICE有值,另一行MGROUP有值、SERVICE为空,合并后会得到两个字段都有值的唯一行。
方案2:处理空值后再分组(核心键可能为空时)
如果MATERIAL也可能为空,且你需要把同一SALES_ORG下空MATERIAL的行合并成一组,可以用COALESCE给空值生成一个临时分组键,避免空值被单独分区:
SELECT SALES_ORG, -- 分组后如果有非空的MATERIAL就返回,否则保留空值 CASE WHEN MAX(MATERIAL) IS NOT NULL THEN MAX(MATERIAL) ELSE NULL END AS MATERIAL, MAX(MGROUP) AS MGROUP, MAX(SERVICE) AS SERVICE FROM SALES GROUP BY SALES_ORG, -- 给空MATERIAL分配和SALES_ORG绑定的临时键,确保同组 COALESCE(MATERIAL, 'TEMP_GROUP_' || SALES_ORG)
方案3:用窗口函数去重(不想用GROUP BY时)
如果你更倾向于用窗口函数,可以先按核心键分区提取非空值,再用DISTINCT去重得到唯一组合:
SELECT DISTINCT SALES_ORG, MAX(MATERIAL) OVER (PARTITION BY SALES_ORG, COALESCE(MATERIAL, 'TEMP_GROUP_' || SALES_ORG)) AS MATERIAL, MAX(MGROUP) OVER (PARTITION BY SALES_ORG, COALESCE(MATERIAL, 'TEMP_GROUP_' || SALES_ORG)) AS MGROUP, MAX(SERVICE) OVER (PARTITION BY SALES_ORG, COALESCE(MATERIAL, 'TEMP_GROUP_' || SALES_ORG)) AS SERVICE FROM SALES
这个思路和方案2类似,只是用窗口函数替代了GROUP BY,最后通过DISTINCT去掉重复的合并行。
内容的提问来源于stack exchange,提问作者Mani

