排除 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 驱动程序
Excel 2007 MS Query 中的多部分标识符错误,但 SQL Server 2008 中没有