cha*_*win 5 sql t-sql sql-server
我正在使用的数据相当复杂,所以我将提供一个更简单的示例,以便我可以将其扩展到我正在处理的内容.
注意:我已经找到了一种方法,但它非常慢且不可扩展.它适用于小型数据集,但是如果我将它应用到需要运行的实际表中,则需要永远.
我需要删除表中的所有重复数据子集.删除重复行很容易,但我发现找到一种有效的方法来删除重复的子集.
例:
GroupID Subset Value
------- ---- ----
1 a 1
1 a 2
1 a 3
1 b 1
1 b 3
1 b 5
1 c 1
1 c 3
1 c 5
2 a 1
2 a 2
2 a 3
2 b 4
2 b 5
2 b 6
2 c 1
2 c 3
2 c 6
Run Code Online (Sandbox Code Playgroud)
所以在这个例子中,从GroupID 1开始,我需要删除子集'b'或子集'c',因为它们都包含值1,2,3并不重要.对于GroupID 2,没有任何集重复,因此不会删除任何集.
这是我用来小规模解决这个问题的代码.它工作得很好,但是当应用到超过100万条记录时...你可以想象它会非常慢(后来我被告知记录的数量,我得到的样本数据要小得多)......:
DECLARE @values TABLE (GroupID INT NOT NULL, SubSet VARCHAR(1) NOT NULL, [Value] INT NOT NULL)
INSERT INTO @values (GroupID, SubSet, [Value])
VALUES (1,'a',1),(1,'a',2),(1,'a',3) ,(1,'b',1),(1,'b',3),(1,'b',5) ,(1,'c',1),(1,'c',3),(1,'c',5),
(2,'a',1),(2,'a',2),(2,'a',3) ,(2,'b',2),(2,'b',4),(2,'b',6) ,(2,'c',1),(2,'c',3),(2,'c',6)
SELECT *
FROM @values v
ORDER BY v.GroupID, v.SubSet, v.[Value]
SELECT x.GroupID, x.NameValues, MIN(x.SubSet)
FROM (
SELECT t1.GroupID, t1.SubSet
, NameValues = (SELECT ',' + CONVERT(VARCHAR(10), t2.[Value]) FROM @values t2 WHERE t1.GroupID = t2.GroupID AND t1.SubSet = t2.SubSet ORDER BY t2.[Value] FOR XML PATH(''))
FROM @values t1
GROUP BY t1.GroupID, t1.SubSet
) x
GROUP BY x.GroupID, x.NameValues
Run Code Online (Sandbox Code Playgroud)
我在这里所做的就是按GroupID和Subset进行分组,并将所有值连接成逗号分隔的字符串......然后将其分组并分组在GroupID和Value列表上,并获取MIN子集.
您可以对一组行使用 checksum_agg()。如果校验和相同,则有力地证明分组字段中的“值”列相等。
在下面的“getChecksums”cte 中,我按组和子集进行分组,并根据您的“值”列进行校验和。
在“maybeBadSubsets”cte 中,我在每个聚合上放置了一个 row_number,以便在校验和匹配的情况下识别第 2+ 行。
最后,我删除如此标识的任何子组。
with
getChecksums as (
select groupId,
subset,
cs = checksum_agg(value)
from @values v
group by groupId,
subset
),
maybeBadSubsets as (
select groupId,
subset,
cs,
deleteSubset =
case
when row_number() over (
partition by groupId, cs
order by subset
) > 1
then 1
end
from getChecksums
)
delete v
from @values v
where exists (
select 0
from maybeBadSubsets mbs
where v.groupId = mbs.groupId
and v.SubSet = mbs.subset
and mbs.deleteSubset = 1
);
Run Code Online (Sandbox Code Playgroud)
我不知道校验和匹配的确切可能性是多少。如果您对误报率不满意,您仍然可以使用它以更具算法性的方法消除一些分支,以大幅提高性能。
注意:CTE 在性能方面可能会有一些奇怪的情况。如果您发现查询引擎正在为 @values 的每一行运行“maybeBadSubsets”,则您可能需要在使用之前将其结果放入临时表或表变量中。但我相信只要有“存在”就可以了。
编辑:
我没有注意到,但正如OP注意到的那样,checksum_agg似乎在错误命中/未命中方面表现得很差。我怀疑这可能是由于输入的简单性造成的。我变了
cs = checksum_agg(value)
Run Code Online (Sandbox Code Playgroud)
以上至
cs = checksum_agg(convert(int,hashbytes('md5', convert(char(1),value))))
Run Code Online (Sandbox Code Playgroud)
并得到了更好的结果。但我不知道它在更大的数据集上的表现如何。