排除 MS SQL Server 2008 中的“某些”重复行

Posted

技术标签:

【中文标题】排除 MS SQL Server 2008 中的“某些”重复行【英文标题】:Excluding "some" duplicate rows in MS SQL Server 2008 【发布时间】:2021-12-24 07:43:47 【问题描述】:

-- 有什么建议可以让它在 MS SQL Server 2008 中工作?

-- 我对“重复行”的定义是“前 3 个字段匹配” -- 我需要从结果中排除重复项,但我决定保留哪一行 -- 保留第 4 列有值的行(每组重复对只有 1 行)

-- 结果将保留第 2 行(但不保留第 1 行) -- 也保留第 3 行(但不保留第 4 行) -- 同时保留所有剩余的行(没有重复) -- 应该返回 10 行中的 8 行

IF(OBJECT_ID('tempdb..#tmp') IS NOT NULL)       DROP TABLE #tmp

CREATE TABLE #tmp
(
    aKey Int            IDENTITY(1,1)   PRIMARY KEY,    
    
    f1 VarChar(10)          NOT NULL    DEFAULT 0,  -- 1
    f2 VarChar(10)          NOT NULL    DEFAULT 0,  -- 2
    f3 VarChar(10)          NOT NULL    DEFAULT 0,  -- 3 
    f4 VarChar(10)          NOT NULL    DEFAULT 0,
    f5 VarChar(10)          NOT NULL    DEFAULT 0,
    f6 VarChar(10)          NOT NULL    DEFAULT 0
)

INSERT INTO #tmp(f1, f2, f3, f4, f5, f6)    VALUES('A', 'B', 'C', '' , 'del', '1') -- 1st of the duplicate
INSERT INTO #tmp(f1, f2, f3, f4, f5, f6)    VALUES('A', 'B', 'C', 'D', 'keep', '1') -- 2nd of the duplicate

INSERT INTO #tmp(f1, f2, f3, f4, f5, f6)    VALUES('D', 'E', 'F', 'G', 'keep', '2') -- 1st of the duplicate
INSERT INTO #tmp(f1, f2, f3, f4, f5, f6)    VALUES('D', 'E', 'F', '' , 'del', '2') -- 2nd of the duplicate

INSERT INTO #tmp(f1, f2, f3, f4, f5, f6)    VALUES('H', 'G', 'N', 'Q', '1', 'K')  
INSERT INTO #tmp(f1, f2, f3, f4, f5, f6)    VALUES('I', 'G', 'C', '' , '2', 'L')  
INSERT INTO #tmp(f1, f2, f3, f4, f5, f6)    VALUES('J', 'H', 'D', 'R', '3', 'P')  
INSERT INTO #tmp(f1, f2, f3, f4, f5, f6)    VALUES('K', 'G', 'C', '' , '4', 'K')  
INSERT INTO #tmp(f1, f2, f3, f4, f5, f6)    VALUES('L', 'G', 'C', 'S', '5', 'V')  
INSERT INTO #tmp(f1, f2, f3, f4, f5, f6)    VALUES('K', 'M', 'C', '' , '6', 'K')  

--SELECT * FROM #tmp

-- This "almost" works, but is excluding too many non-duplicate rows:

SELECT DISTINCT t1.* FROM #tmp AS t1
INNER JOIN #tmp AS t2
ON t1.f1 = t2.f1 AND t1.f2 = t2.f2 AND t1.f3 = t2.f3
WHERE t1.f4 <> ''

【问题讨论】:

如果您有两条记录的值在第 4 列但匹配前的 3 列,会发生什么情况?本质上,您想使用 row_number() over (partition by f1,f2,f3, f4 desc) 并仅返回第 1 行这会将行号分配给 ech“Like”副本,然后仅返回第一行。但考虑到您的条件是只返回具有 f4 值的那些......在确定要使用哪个记录时太模糊了。 【参考方案1】:

首先,以人们可以使用的格式发布示例数据的出色工作。太棒了!!!!这使人们很容易提供帮助。其次,即使您陈述的解释并不完全清楚,您确实在样本数据中提供了足够的详细信息,以明确您需要完成什么。 xQbert 发现使用 ROW_NUMBER 是解决此问题的好方法。

我在这里使用了一个 cte 来说明它是如何工作的。如果您愿意,您可以将其作为子查询轻松完成。

with SortedValues as
(
    select *
        , RowNum = ROW_NUMBER() over (partition by f1, f2, f3 order by f4 desc)
    from #tmp
)

select *
from SortedValues
where RowNum = 1
order by aKey

【讨论】:

也许最好也解释一下空字符串 ''NULL 在其他任何东西之前排序(或者如果排序是 DESC 则在之后) 优点@Charlieface。 我发现“嵌套方法”更容易理解。但是当我尝试“with/as/over/partition”方法时(我第一次使用它)......它也同样有效。太棒了!另外,我现在可以在未来的项目中使用“with/as/over/partition”,因为它真的不难理解。【参考方案2】:

与您现有的方法保持一致,而不是加入,只需使用exists

select * 
from t
where not exists (
    select * from t t2 
    where t.f1=t2.f1 
        and t.f2=t2.f2 
        and t.f3=t2.f3 
        and t.f4 =''
        and t2.akey !=t.akey
    )

【讨论】:

这不太可能像行编号方法那样有效 这将对表格进行更多的逻辑读取,行号将需要对行进行排序;对真实世界数据的测试显然会显示哪个是最好的 不一定是这种情况:exists 可能会被转换为排序合并连接并且@SeanLange 查询中的最后一个order by 实际上并不是必需的。我承认如果有很大比例的行重复,您的解决方案可能会更快,但这是不寻常的。同意需要对真实数据进行测试 @Charlieface 实际上没有最终顺序,就无法确定输出中行的顺序。如果顺序无关紧要,那么您是正确的。

以上是关于排除 MS SQL Server 2008 中的“某些”重复行的主要内容,如果未能解决你的问题,请参考以下文章

ODBC:用于 MS Access 的 SQL Server 2008 驱动程序

MS SQL Server 2008 R2 常规操作

Excel 2007 MS Query 中的多部分标识符错误,但 SQL Server 2008 中没有

ms sql2012 能否安装在win2008 server

如何找到 MS SQL Server 2008 的端口?

将 php 连接到 MS SQL Server 2008