You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

去除重复行:仅移除重复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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:39:19