首页 > 解决方案 > SQL。根据多个条件删除重复记录

问题描述

我有一个TABLE名为 Food 的几千条记录。每条记录是一个由描述和 5 个类别组成的食物。随后的每个类别都比上一个类别更具体。描述、cat1 和 cat2 不能接受NULL值。Cat3、cat4 和 cat5 可以接受NULL值。

例如:

description | cat1 | cat2    | cat3  | cat4      | cat5
Green apple | Food | produce | NULL  | apple     | NULL
Root beer   | Bev  | Non-Alc | NULL  | Root beer | NULL

我遇到的问题是有很多重复的描述分配了不同的类别。我需要帮助编写一个可以在某些条件下删除这些重复项的代码。

例子:

description    | cat1 | cat2     | cat3     | cat4  | cat5
Mango Syrup    | Food | Produce  | NULL     | Mango | NULL
Mango Syrup    | Food | Dry Good | NULL     | NULL  | Syrup
Pepperoni Pizza| Food | Meat     | Pepperoni| NULL  | NULL
Pepperoni Pizza| Food | Bakery   | NULL     | Pizza | NULL

我有数百个,幸运的是,它们的设置方式都相同。在 cat3、4 和 5 三列中,只能填充一列。如果记录的 cat5 IS NOT NULL, cat3 和 cat4 将是NULL。如果记录的 cat4 IS NOT NULL, cat3 和 cat5 将是NULL。如果记录的 cat3 IS NOT NULL, cat4 和 cat5 将是NULL

正确的副本是其记录中填充了最具体类别的项目。应删除所有其他重复项。

我尝试过的事情: GROUP BY并使用MIN()MAX()聚合不同的类别。这并没有给我想要的结果。

任何事情都会有所帮助。欣赏它。

标签: sqlsql-serverduplicatescategoriessql-delete

解决方案


因此,对于每个描述,您都希望填充“最大”类别的行。

一种方法使用row_number()

select t.*
from (select t.*,
             row_number() over (partition by description
                                order by case when cat5 is null then 1
                                              when cat4 is null then 2
                                              when cat3 is null then 3
                                              when cat2 is null then 4
                                              when cat1 is null then 5
                                         end
                                ) as seqnum
      from t
     ) t
where seqnum = 1;

如果您确实想删除其他行,请使用可更新的 CTE:

with todelete as (
      select t.*
      from (select t.*,
                   row_number() over (partition by description
                                      order by case when cat5 is null then 1
                                                    when cat4 is null then 2
                                                    when cat3 is null then 3
                                                    when cat2 is null then 4
                                                    when cat1 is null then 5
                                               end
                                      ) as seqnum
            from t
           ) t
      )
delete from todelete
    where seqnum > 1;

推荐阅读