web-dev-qa-db-ja.com

PostgreSQLの重複レコードを削除する

PostgreSQL 8.3.8データベースにテーブルがあり、そのテーブルにはキー/制約がなく、まったく同じ値を持つ複数の行があります。

すべての重複を削除し、各行のコピーを1つだけ保持したいと思います。

重複を識別するために使用できる特定の列(「キー」)があります(つまり、各「キー」ごとに1つのエントリのみが存在する必要があります)。

これどうやってするの? (理想的には単一のSQLコマンドで)この場合、速度は問題になりません(数行しかありません)。

89
André Morujão
DELETE FROM dupes a
WHERE a.ctid <> (SELECT min(b.ctid)
                 FROM   dupes b
                 WHERE  a.key = b.key);
62

より高速なソリューションは

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
141
rapimo

これは高速で簡潔です:

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

一意の識別子なしで重複行を削除する方法 の私の回答も参照してください。これには詳細が含まれています。

46
isapir

私はこれを試しました:

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 wikiにより提供:

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

14
Radu Gabriel

独自のバージョンを作成する必要がありました。 @a_horse_with_no_nameによって記述されたバージョンは、テーブル(21M行)で非常に遅いです。また、@ rapimoは重複を削除しません。

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);
6
expert

私は一時テーブルを使用します:

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

次に、tabを削除し、tab_tempの名前をtabに変更します。

5

これは私にとってはうまくいきました。重複した値を含む用語、テーブルがありました。クエリを実行して、すべての重複行を一時テーブルに追加します。次に、一時テーブルにこれらのIDを指定してdeleteステートメントを実行しました。 valueは、重複を含む列です。

        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)
0
Beanwah