【问题标题】:Delete all but one duplicate record删除除一条重复记录外的所有记录
【发布时间】:2011-08-18 11:11:58
【问题描述】:

我有一个表应该跟踪给定配置文件的访问者(用户 ID 到用户 ID 对)。事实证明我的 SQL 查询有点不对劲,并且按预期生成了多对而不是单对。事后看来,我应该对每个 id+id 对强制执行唯一约束。

现在,我该如何清理桌子?我想要做的是删除所有重复的对,只留下一个。

所以例如改变这个:

23515 -> 52525 date_visited
23515 -> 52525 date_visited
23515 -> 52525 date_visited
12345 -> 54321 date_visited
12345 -> 54321 date_visited
12345 -> 54321 date_visited
12345 -> 54321 date_visited
23515 -> 52525 date_visited
...

进入这个:

23515 -> 52525 date_visited
12345 -> 54321 date_visited

更新:这是所要求的表结构:

id  int(10)         UNSIGNED    Non     Aucun   AUTO_INCREMENT
profile_id  int(10)         UNSIGNED    Non     0 
visitor_id  int(10)         UNSIGNED    Non     0
date_visited    timestamp           Non     CURRENT_TIMESTAMP   

【问题讨论】:

  • 请问表结构是什么?是否有第 3 列用于平局值?
  • @gbn:表结构已添加(MySQL)。第三列是跟踪用户上次访问个人资料的时间。该结构可能应该通过对 profile_id 和 visitor_id 的约束进行修改。 P.S:我现在没有填充表的 SQL,但它类似于if exists update timestamp if not create record

标签: sql sql-delete


【解决方案1】:

ANSI SQL 解决方案

在子查询中使用 group by:

delete from my_tab where id not in 
(select min(id) from my_tab group by profile_id, visitor_id);

您需要某种唯一标识符(这里,我使用的是 id)。

MySQL 解决方案

正如@JamesPoulson 所指出的,这会导致 MySQL 出现语法错误;正确的解决方案是(如James' answer所示):

delete from `my_tab` where id not in
( SELECT * FROM 
    (select min(id) from `my_tab` group by profile_id, visitor_id) AS temp_tab
);

【讨论】:

  • 很好的解决方案。我没想过按(经验>知识)使用小组。这会显示Can't specify target in FROM clause,但有一个解决方法(请参阅我的回答)。
  • 注意,这在 MySQL 中不起作用,因为它不允许您修改您在内部选择中使用的表:Error Code: 1093. You can't specify target table 'my_tab' for update in FROM clause
  • 我已经更新了答案;我最初认为人们会阅读@JamesPoulson 的评论/答案并使用他们的版本,但显然情况并非总是如此。
  • 没有id键怎么办?
  • 非常优雅的解决方案。有时最好使用 MAX 而不是 MIN,这样您就可以保留可能最正确的行的最新版本。
【解决方案2】:

这是Frank Schmitt's solution 的一个小变通方法,利用临时表允许他的解决方案在 MySQL 上运行:

delete from `my_tab` where id not in
( SELECT * FROM 
    (select min(id) from `my_tab` group by profile_id, visitor_id) AS temp_tab
)

【讨论】:

  • @FrankSchmitt 很好:)
【解决方案3】:

这将起作用:

With NewCTE
AS
(
Select *, Row_number() over(partition by ID order by ID)as RowNumber from 
table_name
)
Delete from NewCTE where RowNumber > 1

【讨论】:

  • 如果您的表中没有唯一标识符并且不想创建临时表,则此答案是最好的。
【解决方案4】:

选择所有唯一的行
将它们复制到新的临时表
截断原始表
将临时表数据复制到原始表

这就是我要做的。我不确定是否有 1 个查询可以为您完成所有这些操作。

【讨论】:

  • 使用临时表是一种很好的反射,实际上是必要的。如果有大量数据,这可能是一种更适合的方法。
【解决方案5】:

如果您使用的是 SQL,您可以手动删除保留一个条目的重复行,只需遵循以下过程:

  1. 进入有重复数据的表格。
  2. 应用过滤器来隔离每个 id 的重复数据
  3. 选择您要删除的所有行。
  4. 按删除并保存结果。
  5. 为每个有重复条目的 ID 重复该过程。

这是一个漫长的过程,但您可以立即实时看到结果。

希望这个解决方案对你有用!!

【讨论】:

  • 许多使用这些答案的人正在处理数百万(甚至数十亿)行。手动执行此操作需要数周时间。
  • 世界上有什么
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-17
  • 1970-01-01
  • 2012-10-01
  • 2011-11-06
  • 2019-06-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多