2011-07-05 165 views
40

我有一个表在一个PostgreSQL 8.3.8数据库,其上有没有钥匙/制约因素,并具有完全相同的价值多行。删除重复记录在PostgreSQL的

我想删除所有重复,只保留1每行的副本。

有特别是一个柱(命名为“键”),其可以被用于识别重复的(即,应该只存在为每个不同的“密钥”的一个条目)。

我该怎么做? (最好有一个SQL命令) 速度是不是在这种情况下,一个问题(只有几行)。

回答

39
DELETE FROM dupes a 
WHERE a.ctid <> (SELECT min(b.ctid) 
       FROM dupes b 
       WHERE a.key = b.key); 
+0

完美,谢谢!我不知道ctid –

+4

不要使用它,它太慢了! –

+2

尽管这个解决方案肯定有效,但@rapimo的[下面的解决方案](https://stackoverflow.com/a/12963112/1156554)执行得更快。我认为这与内部select语句执行N次(对于dupes表中的所有N行)而不是另一个解决方案中正在执行的分组有关。 – David

4

我会用一个临时表:

create table tab_temp as 
select distinct f1, f2, f3, fn 
    from tab; 

然后,删除tab和重命名tab_temptab

+4

这种做法并不占触发器,索引和统计。当然,你可以添加它们,但它也增加了很多工作。 – Jordan

+0

不是每个人都需要这个。这种方法非常快速,比没有索引的200k电子邮件(varchar 250)更好。 –

58

一个更快的解决方案是

DELETE FROM dups a USING (
     SELECT MIN(ctid) as ctid, key 
     FROM dups 
     GROUP BY key HAVING COUNT(*) > 1 
    ) b 
     WHERE a.key = b.key 
     AND a.ctid <> b.ctid 
+14

为什么它比a_horse_with_no_name的解决方案更快? – Roberto

+1

这是在我的测试中第二次执行,而接受的解决方案是53分钟。 – Alex

+0

确实速度更快! – Alfabravo

5

我要创建我自己的版本。由@a_horse_with_no_name编写的版本在我的表(21M行)上太慢了。而@rapimo根本不会删除dups。

以下是我对PostgreSQL的9.5

DELETE FROM your_table 
WHERE ctid IN (
    SELECT unnest(array_remove(all_ctids, actid)) 
    FROM (
     SELECT 
      min(b.ctid)  AS actid, 
      array_agg(ctid) AS all_ctids 
     FROM your_table b 
     GROUP BY key1, key2, key3, key4 
     HAVING count(*) > 1) c); 
11

使用我尝试这样做:

DELETE FROM tablename 
WHERE id IN (SELECT id 
       FROM (SELECT id, 
          ROW_NUMBER() OVER (partition BY column1, column2, column3 ORDER BY id) AS rnum 
        FROM tablename) t 
       WHERE t.rnum > 1); 
由Postgres的维基提供

https://wiki.postgresql.org/wiki/Deleting_duplicates

+0

与@ rapimo的答案和接受的答案(@a_horse_with_no_name)相比的性能的任何想法? – tuxayo

+1

如果像问题状态一样,_all_列是相同的,那么这个将不起作用,包括'id'。 – ibizaman

0

这对我行之有效。我有一张表,包含重复值的术语。执行查询以填充所有重复行的临时表。然后我用临时表中的这些id运行了一条delete语句。值是包含重复项的列。

 CREATE TEMP TABLE dupids AS 
     select id from (
        select value, id, row_number() 
over (partition by value order by value) 
    as rownum from terms 
       ) tmp 
        where rownum >= 2; 

delete from [table] where id in (select id from dupids) 
-2

既适用于普通的SQL和PostgreSQL(也能在AWS红移)

DROP TABLE IF EXISTS backupOfTheTableContainingDuplicates; 

CREATE TABLE aNewEmptyTemporaryOrBackupTable 
AS SELECT DISTINCT * FROM originalTableContainingDuplicates; 

TRUNCATE TABLE originalTableContainingDuplicates; 

INSERT INTO originalTableContainingDuplicates SELECT * FROM 
aNewEmptyTemporaryOrBackupTable ; 

DROP TABLE aNewEmptyTemporaryOrBackupTable ; 

说明上述SQL脚本

所以,

第1查询可以确保,如果您有任何原始表包含备份/临时表g重复,然后首先删除该表。

的第二查询,创建一个新的表(临时/备份)表与包含重复原始表的唯一条目,所以新的临时表是相同的与原始表减去重复条目。

第三查询,截断或清空原来的表。

第四个查询,将临时表中的所有唯一条目插入或复制到最近被截断的原始表(因此没有数据)。执行此查询后,原始表将填充临时表中的UNIQUE数据。

第五个查询,删除/删除不必要的临时表。

所以最终结果是,原始表只有唯一的条目,没有重复。

5

这是快速和简洁:

DELETE FROM dupes T1 
    USING dupes T2 
WHERE T1.ctid < T2.ctid -- delete the older versions 
    AND T1.key = T2.key; -- add more columns if needed 
+0

这是优秀的! – user151496