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

SQL基于指定列去重:合并多源查询结果时忽略日期列

解决UNION查询中忽略日期列去重的问题

嘿,我完全懂你现在的困扰——原本想合并两个数据源的软件安装记录,结果因为日期列的差异(有的有值有的空,或者值不一样),导致明明是同一台机器同一个软件的记录,却被当成不同结果保留下来了对吧?从你贴的示例图也能看到,同一台CH开头机器上的同一个软件,因为InstallDate和InstallDate2的不同出现了重复,咱们调整下查询逻辑就能搞定!

核心思路是:先把两个数据源的所有记录合并,然后按你想要唯一的四个字段(PCName、Vendor、Product、Version)分组,每组只保留一条记录(日期字段可以选择取非空值,或者优先保留某一个数据源的日期)。下面给你两种常用的解决方案:

方案一:分组聚合(简单高效,适合不在乎日期取哪一个的场景)

先用UNION ALL合并两个数据源的所有记录(比UNION更高效,因为不需要提前去重),然后按四个关键字段分组,日期字段用聚合函数取非空值:

WITH CombinedData AS (
    -- 第一个数据源的查询
    SELECT 
        SYS.Netbios_Name0 as PCName, 
        ARP.Publisher0 as Vendor, 
        ARP.DisplayName0 as Product, 
        ARP.Version0 as Version, 
        REPLACE(REPLACE(CONVERT(varchar,ARP.InstallDate0,120),'-',''),' 00:00:00','') as InstallDate,
        REPLACE(REPLACE(CONVERT(varchar,ARP.InstallDate0,120),'-',''),' 00:00:00','') as InstallDate2
    FROM v_Add_Remove_Programs ARP 
    JOIN v_R_System SYS ON ARP.ResourceID=SYS.ResourceID 
    WHERE SYS.Netbios_Name0 like 'CH-%' and InstallDate0 NOT LIKE ''
    
    UNION ALL -- 用UNION ALL避免不必要的去重,提升性能
    
    -- 第二个数据源的查询
    SELECT 
        SYS.Netbios_Name0 as PCName, 
        SP.CompanyName as Vendor, 
        SP.ProductName as Product, 
        SP.ProductVersion as Version, 
        REPLACE(REPLACE(CONVERT(varchar,MARP.InstallDate0,120),'-',''),' 00:00:00','') as InstallDate,
        REPLACE(REPLACE(CONVERT(varchar,GSI.InstallDate0,120),'-',''),' 00:00:00','') as InstallDate2
    FROM v_GS_SoftwareProduct SP 
    JOIN v_R_System SYS ON SP.ResourceID=SYS.ResourceID 
    LEFT JOIN v_GS_Mapped_Add_Remove_Programs MARP ON SP.ResourceID = MARP.ResourceID 
        AND RTRIM(LTRIM(UPPER(SP.ProductName))) LIKE RTRIM(LTRIM(UPPER(MARP.DisplayName0))) 
        AND RTRIM(LTRIM(UPPER(SP.ProductVersion))) LIKE RTRIM(LTRIM(UPPER(MARP.Version0))) 
    LEFT JOIN v_GS_INSTALLED_SOFTWARE GSI ON SP.ResourceID = GSI.ResourceID 
        AND RTRIM(LTRIM(UPPER(SP.ProductName))) LIKE RTRIM(LTRIM(UPPER(GSI.ProductName0))) 
        AND RTRIM(LTRIM(UPPER(SP.ProductVersion))) LIKE RTRIM(LTRIM(UPPER(GSI.ProductVersion0))) 
    Where SYS.Netbios_Name0 Like 'CH-%' AND (MARP.InstallDate0 NOT LIKE '' OR GSI.InstallDate0 NOT LIKE '')
)
-- 分组去重,日期取非空值
SELECT 
    PCName,
    Vendor,
    Product,
    Version,
    COALESCE(MAX(InstallDate), '') as InstallDate, -- 取该组中第一个非空的InstallDate
    COALESCE(MAX(InstallDate2), '') as InstallDate2
FROM CombinedData
GROUP BY PCName, Vendor, Product, Version -- 按四个关键字段分组
ORDER By PCName, Vendor, Product, Version

方案二:窗口函数(适合优先保留某一个数据源记录的场景)

如果想优先保留第一个数据源(v_Add_Remove_Programs)的记录,只有当第一个数据源没有的时候才取第二个的,可以给每个数据源标记优先级,用窗口函数排序后取每组第一条:

WITH CombinedData AS (
    -- 第一个数据源,标记优先级为1(更高优先级)
    SELECT 
        SYS.Netbios_Name0 as PCName, 
        ARP.Publisher0 as Vendor, 
        ARP.DisplayName0 as Product, 
        ARP.Version0 as Version, 
        REPLACE(REPLACE(CONVERT(varchar,ARP.InstallDate0,120),'-',''),' 00:00:00','') as InstallDate,
        REPLACE(REPLACE(CONVERT(varchar,ARP.InstallDate0,120),'-',''),' 00:00:00','') as InstallDate2,
        1 as SourcePriority
    FROM v_Add_Remove_Programs ARP 
    JOIN v_R_System SYS ON ARP.ResourceID=SYS.ResourceID 
    WHERE SYS.Netbios_Name0 like 'CH-%' and InstallDate0 NOT LIKE ''
    
    UNION ALL
    
    -- 第二个数据源,标记优先级为2(更低优先级)
    SELECT 
        SYS.Netbios_Name0 as PCName, 
        SP.CompanyName as Vendor, 
        SP.ProductName as Product, 
        SP.ProductVersion as Version, 
        REPLACE(REPLACE(CONVERT(varchar,MARP.InstallDate0,120),'-',''),' 00:00:00','') as InstallDate,
        REPLACE(REPLACE(CONVERT(varchar,GSI.InstallDate0,120),'-',''),' 00:00:00','') as InstallDate2,
        2 as SourcePriority
    FROM v_GS_SoftwareProduct SP 
    JOIN v_R_System SYS ON SP.ResourceID=SYS.ResourceID 
    LEFT JOIN v_GS_Mapped_Add_Remove_Programs MARP ON SP.ResourceID = MARP.ResourceID 
        AND RTRIM(LTRIM(UPPER(SP.ProductName))) LIKE RTRIM(LTRIM(UPPER(MARP.DisplayName0))) 
        AND RTRIM(LTRIM(UPPER(SP.ProductVersion))) LIKE RTRIM(LTRIM(UPPER(MARP.Version0))) 
    LEFT JOIN v_GS_INSTALLED_SOFTWARE GSI ON SP.ResourceID = GSI.ResourceID 
        AND RTRIM(LTRIM(UPPER(SP.ProductName))) LIKE RTRIM(LTRIM(UPPER(GSI.ProductName0))) 
        AND RTRIM(LTRIM(UPPER(SP.ProductVersion))) LIKE RTRIM(LTRIM(UPPER(GSI.ProductVersion0))) 
    Where SYS.Netbios_Name0 Like 'CH-%' AND (MARP.InstallDate0 NOT LIKE '' OR GSI.InstallDate0 NOT LIKE '')
),
RankedData AS (
    -- 给每组(PCName、Vendor、Product、Version)的记录按优先级排序
    SELECT 
        *,
        ROW_NUMBER() OVER (PARTITION BY PCName, Vendor, Product, Version ORDER BY SourcePriority) as RowNum
    FROM CombinedData
)
-- 只取每组的第一条记录
SELECT 
    PCName,
    Vendor,
    Product,
    Version,
    InstallDate,
    InstallDate2
FROM RankedData
WHERE RowNum = 1
ORDER By PCName, Vendor, Product, Version

小提示

  • 如果日期列你完全不在乎具体值,方案一的分组聚合更简单直接;
  • 如果想优先保留某一个数据源的日期信息,方案二的窗口函数更灵活;
  • 用UNION ALL代替UNION是因为UNION会自动去重,但这里因为日期不同去不了,反而会增加不必要的性能开销,所以用UNION ALL更高效。

内容的提问来源于stack exchange,提问作者ssoong

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:09:11