在 SQL 中删除重复组

Posted

技术标签:

【中文标题】在 SQL 中删除重复组【英文标题】:In SQL remove duplicate groups 【发布时间】:2021-03-05 20:51:53 【问题描述】:

在 SQL Server 中,查询后我有以下数据集。我需要按 uid 对这些数据进行分组,然后删除“重复项”并返回具有最新列 D 的分组。我还需要返回 2 个最近的去重组。如果满足以下条件,则将组定义为重复:

行数相同 A、B、C 列相同 行的顺序是一样的
Uid A B C D1 D2
1 6 1 2 2021-02-19 2021-02-19 09:00:00
1 6 2 1 2021-02-19 2021-02-19 10:00:00
1 6 1 2 2021-02-19 2021-02-19 11:00:00
2 6 1 2 2021-01-19 2021-01-19 09:00:00
2 6 2 1 2021-01-19 2021-01-19 10:00:00
3 6 1 2 2020-02-19 2020-02-19 09:00:00
3 6 2 1 2020-02-19 2020-02-19 10:00:00
3 6 1 2 2020-02-19 2020-02-19 11:00:00
4 11 4 5 2000-10-05 2000-10-05 09:00:00

例如,在上面的数据集中,uid 的 1 和 3 是重复的,其中 1 是最近的。因此上述数据集应该返回

Uid A B C D1 D2
1 6 1 2 2021-02-19 2021-02-19 09:00:00
1 6 2 1 2021-02-19 2021-02-19 10:00:00
1 6 1 2 2021-02-19 2021-02-19 11:00:00
2 6 1 2 2021-01-19 2021-01-19 09:00:00
2 6 2 1 2021-01-19 2021-01-19 10:00:00

我尝试了以下窗口功能:

FROM (

  SELECT 
    A,
    B,
    C,
    D1,
    D2,
    ROW_NUMBER() over (partition by 
                                    Uid                                    
                                    ORDER BY D2 DESC) as rn
....

where rn = 1

但这不允许我按 uid 分组。我怎样才能做到这一点?

【问题讨论】:

欢迎使用 Stack Overflow 数据库没有“顺序”的概念(除非您可以按某些列对数据进行排序)。查看上面的数据,我明白你所说的 3 是 1 的副本,但是“相同顺序”的概念将分崩离析,缺乏一些机制来实际告诉 RDBMS “顺序”是什么意思。 (在任何数据集上缺少 ORDER BY(具有足够的值来提供唯一性)的任何查询,在重复时可能会以不同的顺序返回数据。) "行的顺序是一样的" -- 你如何定义行的顺序?在没有明确排序的情况下,行没有内在的排序。 @TheImpaler 我将 order 定义为意味着 (6, 1, 2) 然后 (6, 2, 1) 然后 (6, 1, 2) 将匹配 (6, 1, 2) 然后(6, 2, 1) 然后 (6, 1, 2) 获取另一个 uid。 (6, 1, 2) then (6, 1, 2) then (6, 2, 1) 是相同的 3 行的不同顺序。如何使订购明确?谢谢 @ILikeCode "(6, 1, 2) then (6, 2, 1) then (6, 1, 2)" -- 结果集排序是什么?请定义规则。在我看来,您只是幸运地获得了该排序中的行。 @TheImpaler 你是对的。我更新了帖子以显示我用来获取第一个输出的查询。我不确定如何获得第二个输出。谢谢 【参考方案1】:

在下面的查询中,子查询 temp 为 A、B、C 创建了一个逗号分隔的列。然后我在 A、B、C 上使用分区,并在子查询 temp2 级别获得基于日期的排名。外部的最终查询仅提取排名 1 并显示您的表的输出。

select t.Uid, t.A,t.B, t.C , t.D1, t.D2
from (
                    select Uid, A,B,C, D1, rank() over ( partition by A, B,C order by D1 desc) as rank
                    from 
                        (SELECT Uid,  
                    A=STUFF  
                    (  
                         (  
                           SELECT  ', ' + CAST(A AS VARCHAR(MAX))  
                           FROM Table1 t2   
                           WHERE t2.Uid = t1.Uid   
                           FOR XML PATH('')  
                         ),1,1,''  
                    )  ,
                    B=STUFF  
                    (  
                         (              
                           SELECT  ', ' + CAST(B AS VARCHAR(MAX))  
                           FROM Table1 t2   
                           WHERE t2.Uid = t1.Uid   
                           FOR XML PATH('')  
                         ),1,1,''  
                    )  ,
                    C=STUFF  
                    (  
                         (  
                           SELECT  ', ' + CAST(C AS VARCHAR(MAX))  
                           FROM Table1 t2   
                           WHERE t2.Uid = t1.Uid   
                           FOR XML PATH('')  
                         ),1,1,''  
                    )  ,
                    cast (max( [D1] ) as date) D1
                    FROM Table1 t1  
                    GROUP BY Uid  ) as temp 
                    ) as temp2
join Table1 t on temp2.Uid = t.Uid
and temp2. D1= t.D1
where temp2.rank = 1

这里是 DB Fiddle 链接:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=de2127330c2e60d3733bfc9548504142

【讨论】:

谢谢Raseena Abdul。在我的情况下,结果集是涉及多个表的大型查询的结果。有没有办法可以用这个结果集替换 Table1?谢谢 你能把你的输出保存到一个临时表吗?我正在使用 stuff/xml 路径来创建一个逗号分隔文件来比较多行。然后我使用输出来显示你的原始值。所以基本上你需要你的输出两次。此外,如果您使用的是 SQL Server 2017 或更高版本,则可以使用 STRING_AGG 函数创建逗号分隔文件。 :dbfiddle.uk/…

以上是关于在 SQL 中删除重复组的主要内容,如果未能解决你的问题,请参考以下文章

如何从SQL表中删除不是组的最大值的记录[重复]

SAS / PROC SQL - 只要有重复(不只是删除重复),删除BY组中的所有观察

删除 SQL 选择中的重复项

一条SQL删除重复记录,重复的只保留一条

一条SQL删除重复记录,重复的只保留一条

Swift 3:在 uitableviewcell 中删除重复项/将它们分组为 1