【问题标题】:Finding Duplicate Data in Oracle在 Oracle 中查找重复数据
【发布时间】:2011-12-07 23:08:43
【问题描述】:

我有一个包含 500,000 多条记录的表,以及 ID、名字、姓氏和电子邮件地址的字段。我要做的是找到名字和姓氏都重复的行(因为同一个人有两个单独的 ID、电子邮件地址或其他任何东西,它们不止一次出现在表中)。我想我知道如何使用 GROUP BY 查找重复项,这就是我所拥有的:

SELECT first_name, last_name, COUNT(*)
FROM person_table
GROUP BY first_name, last_name
HAVING COUNT(*) > 1

问题是我需要将具有这些重复名称的整行移动到另一个表中。有没有办法找到重复项并获取整行?或者至少也要获得ID?我尝试使用自连接,但返回的行数比表中的行数多。那会是更好的方法吗?任何帮助将不胜感激。

【问题讨论】:

  • 你最好检查一下这些是否真的是同一个人的重复。世界上没有一个John Smith,你知道的:)

标签: database oracle duplicates oracle11g


【解决方案1】:

删除重复行最有效的方法是使用自联接:

DELETE FROM person_table a
 WHERE a.rowid > 
       ANY (SELECT b.rowid
              FROM person_table b
             WHERE a.first_name = b.first_name
               AND a.last_name  = b.last_name);

即使有多个重复行,这也会删除所有重复项。

这里有更多关于删除重复项和不同方法的信息:http://www.dba-oracle.com/t_delete_duplicate_table_rows.htm

希望对你有帮助...

编辑:根据您的 cmets,如果您想选择除一个重复项之外的所有重复项,那么

SELECT *
  FROM person_table a
 WHERE a.rowid > 
       ANY (SELECT b.rowid
              FROM person_table b
             WHERE a.first_name = b.first_name
               AND a.last_name  = b.last_name);

【讨论】:

  • 如果我稍微改变一下它实际上可以工作。问题是我不是要删除它们,而是将它们复制到另一个表中。如果我选择而不是使用它删除,我会得到每个重复名称的第一行以外的所有内容,对吗?
  • 好的,不用担心,很高兴它有帮助。顺便说一句,使用 ROWID 是最快的表访问方法,甚至比使用表的主键还要快。
  • 不得不更改我的评论,我想我错过了每组重复项的一行。很抱歉这样切换,但感谢您的反馈。
  • 是的,该语句将删除除一个重复项之外的所有内容。如果将其更改为 SELECT,它将选择除一个重复项之外的所有重复项。
  • 为什么不是 'a.rowid != ANY' ?我刚才遇到了“a.rowid >”失败的情况(并非所有重复项都已删除)。更改为 'a.rowid != ANY' 帮助...
【解决方案2】:

(first_name, last_name)(last_name, first_name) 上的索引会有所帮助:

SELECT t.*
FROM 
    person_table t
  JOIN      
      ( SELECT first_name, last_name
        FROM person_table
        GROUP BY first_name, last_name
        HAVING COUNT(*) > 1
      ) dup
    ON  dup.last_name = t.last_name
    AND dup.first_name = t.first_name

或:

SELECT t.*
FROM person_table t
WHERE EXISTS
      ( SELECT *
        FROM person_table dup
        WHERE dup.last_name = t.last_name
          AND dup.first_name = t.first_name
          AND dup.ID <> t.ID
      )

【讨论】:

  • 这就是我正在寻找的加入。如此简单,我很惊讶我无法弄清楚。还添加了一个索引,帮助很大。
【解决方案3】:

这将为您提供一个您想要移动/删除/等的 ID。请注意,如果 count(*) > 2,则它不起作用,因为您只能获得 1 个 ID(您可以针对这些情况重新运行查询)。

SELECT max(ID), first_name, last_name, COUNT(*)
FROM person_table
GROUP BY first_name, last_name
HAVING COUNT(*) > 1

编辑:您可以使用 COLLECT 一次获取所有 ID(但要小心,因为您只想移动/删除所有除了一个) p>

【讨论】:

  • 谢谢,迈克尔。快速跟进,我意识到我只得到每个重复一次的名字,无论如何,我需要能够得到所有这些名字。有些已经重复了 40 多次(很奇怪,我知道)。有没有比重新运行查询更简单的方法?
  • 非常感谢,collect 功能正是我所需要的。
【解决方案4】:

要添加另一个选项,我通常使用这个来删除重复项:

delete from person_table
where rowid in (select rid
                  from (select rowid rid, row_number() over
                         (partition by first_name,last_name order by rowid) rn
                          from person_table
                        )
                 where rn <> 1 )

【讨论】:

    猜你喜欢
    • 2020-10-09
    • 1970-01-01
    • 1970-01-01
    • 2018-06-29
    • 1970-01-01
    • 2023-01-13
    • 1970-01-01
    • 2017-05-24
    • 1970-01-01
    相关资源
    最近更新 更多