【问题标题】:How can I find duplicate entries and delete the oldest ones in SQL?如何在 SQL 中查找重复条目并删除最旧的条目?
【发布时间】:2020-12-08 21:43:09
【问题描述】:

我有一个表,它的行是唯一的,除了一列中有一个值(我们称之为“名称”)。另一列是“日期”,即添加到数据库的日期。

我要做的是在“名称”中找到重复的值,然后删除“日期”中日期最旧的值,留下最近的值。

看起来是一个比较简单的查询,但是除了简单的查询,我对SQL知之甚少。

有什么想法吗?

【问题讨论】:

  • 您运行的是什么版本的 SQL Server?
  • @KZA:谢谢。我在等待是否可以使用“dense_rank”。 “dense_rank”使这种查询更容易

标签: sql sql-server


【解决方案1】:

查找重复并删除最旧的

这是代码

create table #Product (
    ID      int identity(1, 1) primary key,
    Name        varchar(800),
    DateAdded   datetime default getdate()
)

insert  #Product(Name) select 'Chocolate'
insert  #Product(Name,DateAdded) select 'Candy', GETDATE() + 1
insert  #Product(Name,DateAdded) select 'Chocolate', GETDATE() + 5
select * from #Product

;with Ranked as (
    select  ID, 
        dense_rank() 
        over (partition by Name order by DateAdded desc) as DupeCount
    from    #Product P
)
delete  R
from    Ranked R
where   R.DupeCount > 1

select * from #Product

【讨论】:

  • 这看起来很棒,非常非常感谢,但是它错误地说 DELETE 语句与另一个表中的 REFERENCE 约束冲突,我想这会给我带来另一组问题。但是,我可以手动右键单击并删除行吗?
  • 如果您要删除的行被另一个表引用,请先从该表中删除该行;在上面的示例中使用从“Ranked”CTE 检索到的 ID。
【解决方案2】:

从表 a1 中删除 where exists (select * from table a2 where a2.name = a1.name and a2.date > a1.date)

【讨论】:

  • 运行它会给我“'a1' 附近的语法错误。” a1 是其他东西的占位符吗?对不起,如果这是一个愚蠢的问题:)
  • 问题可能是查询中的“table”实际上应该是包含 Name 和 Date 列的表的名称,而不是字面意义上的“table”一词,这在此上下文中是不允许的因为它是一个 SQL 关键字。
【解决方案3】:

您可以通过自联接和 IS NOT NULL 来实现这一点。

加入 DELETE 查询可能有点危险,因为在某些情况下,它越复杂,删除的风险就越大。

但我会喜欢它。

DELETE
  a.*
FROM
  mytable AS a
  LEFT JOIN mytable AS b ON
    b.date > a.date
    AND (b.name=a.name OR (b.date = a.date AND b.rowid>a.rowid))
WHERE
  AND b.rowid IS NOT NULL

连接和 IS NOT NULL 查找存在具有相同名称的新行的每一行。它还正确处理具有相同日期的两行的情况 - 如果它们具有相同的日期,那么它会按 rowid(无论是什么)。

希望这样的工作。

【讨论】:

    【解决方案4】:

    我刚刚搜索了一下,发现了这个https://www.sqlshack.com/different-ways-to-sql-delete-duplicate-rows-from-a-sql-table/

    这对我来说似乎最容易阅读/理解:

    DELETE FROM [SampleDB].[dbo].[Employee]
        WHERE ID NOT IN
        (
            SELECT MAX(ID) AS MaxRecordID
            FROM [SampleDB].[dbo].[Employee]
            GROUP BY [FirstName], 
                     [LastName], 
                     [Country]
        );
    

    在您的场景中,您可以按名称分组并选择最大日期而不是 Id

    【讨论】:

    • 他希望按日期列,而不是 id。
    • @MohyEldeen 与他的概念相同,他只需要通过他的 DateAdded 列(或任何只想拥有最新的列)更改列 ID。不是拒绝这个答案的理由......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-27
    • 2016-04-27
    • 1970-01-01
    • 2015-03-21
    • 1970-01-01
    • 2010-12-17
    相关资源
    最近更新 更多