去除重复行:仅移除重复MeterSerialNumber对应的NULL Removaldate行
解决重复仪表SerialNumber下仅移除对应NULL行的问题
嘿,我看你遇到了个典型的重复数据过滤难题:同一个MeterSerialNumber如果同时存在Removaldate非空(已移除)和NULL的行,你只想留非空那行;但对于只有Removaldate为NULL的未移除仪表,得完整保留。你之前的查询栽在COUNT()不统计NULL值的特性上,把所有NULL行都误删了,下面给你两种可行的解决方案:
方法一:用窗口函数标记优先级(推荐)
窗口函数ROW_NUMBER()可以帮我们给每个仪表的行按优先级排序,优先保留有移除日期的行,具体SQL如下:
WITH RankedDevices AS ( SELECT [MeterSerialNumber], [EquipmentType], [InstallDate], [Removaldate], -- 计算Age_M的逻辑和你原来一致 ROUND(DATEDIFF(DAY, InstallDate, CASE WHEN Removaldate IS NULL THEN CONVERT(date, GETDATE()) ELSE Removaldate END)/30.42, 0) AS Age_M, -- 给同序列号的行排序:有移除日期的排第1,NULL排第2 ROW_NUMBER() OVER ( PARTITION BY MeterSerialNumber ORDER BY CASE WHEN Removaldate IS NOT NULL THEN 1 ELSE 2 END ) AS RowRank FROM [DOCDPT].[main].[Tbl_Device_ISU] WHERE EquipmentType IN ('S1','NS','NSS') OR EquipmentType LIKE '%S2%' ) SELECT MeterSerialNumber, EquipmentType, InstallDate, Removaldate AS REM_DATE, Age_M FROM RankedDevices WHERE RowRank = 1 -- 只留每个序列号的第一优先级行 ORDER BY MeterSerialNumber, Removaldate DESC;
逻辑拆解:
PARTITION BY MeterSerialNumber:把数据按仪表序列号分组,每个组内单独处理ORDER BY CASE ...:让有移除日期的行排在最前面,NULL行往后靠- 最后筛选
RowRank=1,就能保证:已移除的仪表留非空行,未移除的仪表留唯一的NULL行
方法二:用EXISTS条件精准过滤
如果你不想用CTE,也可以用EXISTS来判断当前NULL行是否有对应的非空行,从而决定是否保留:
SELECT [MeterSerialNumber], [EquipmentType], [InstallDate], [Removaldate] AS REM_DATE, ROUND(DATEDIFF(DAY, InstallDate, CASE WHEN Removaldate IS NULL THEN CONVERT(date, GETDATE()) ELSE Removaldate END)/30.42, 0) AS Age_M FROM [DOCDPT].[main].[Tbl_Device_ISU] t1 WHERE (EquipmentType IN ('S1','NS','NSS') OR EquipmentType LIKE '%S2%') AND ( -- 情况1:当前行有移除日期,直接保留 t1.Removaldate IS NOT NULL -- 情况2:当前行是NULL,但该仪表没有其他带移除日期的行,才保留 OR NOT EXISTS ( SELECT 1 FROM [DOCDPT].[main].[Tbl_Device_ISU] t2 WHERE t2.MeterSerialNumber = t1.MeterSerialNumber AND t2.Removaldate IS NOT NULL AND (t2.EquipmentType IN ('S1','NS','NSS') OR t2.EquipmentType LIKE '%S2%') ) ) ORDER BY MeterSerialNumber, Removaldate DESC;
逻辑拆解:
- 对于有移除日期的行,直接通过条件被保留
- 对于NULL行,只有当同一个仪表不存在任何带移除日期的行时,才会被保留,完美匹配你的需求
为啥原查询不管用?
你原查询的问题出在GROUP BY Removaldate和HAVING COUNT(distinct removaldate)=1上:
- 首先
GROUP BY包含Removaldate,会把同一个仪表的非空行和NULL行分成两个独立的组,根本没合并; - 其次
COUNT(distinct removaldate)会忽略NULL值,所以NULL组的统计结果是0,会被HAVING条件过滤掉,这就是你丢失所有NULL行的原因。
内容的提问来源于stack exchange,提问作者r.baton
相关产品推荐
相关产品推荐

