小さなテーブルから重複行を削除する 質問する

小さなテーブルから重複行を削除する 質問する

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

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

特に、重複を識別するために使用できる列が 1 つあります (「キー」という名前)。つまり、異なる「キー」ごとにエントリが 1 つだけ存在することになります。

どうすればこれを実行できますか? (理想的には、単一の SQL コマンドを使用します。)
この場合、速度は問題ではありません (行が数行しかないため)。

ベストアンサー1

より速い解決策は次のとおりです。

  • 重複の最初の出現箇所を見つける。
  • 次に、最初の重複発生以外のすべての行を削除します。

次のようになります。

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

このソリューションでは、どの行を保持するかを制御できないことに注意してください。

おもちゃの例

CREATE TABLE people (
    name    varchar(50) NOT NULL,
    surname varchar(50) NOT NULL,
    age     integer NOT NULL
);

INSERT INTO people (name, surname, age) VALUES 
    ('A.', 'Tom', 30),
    ('A.', 'Tom', 10),
    ('B.', 'Tom', 20),
    ('B', 'Chris', 20);

-- The inner command to find duplicates first occurences:
SELECT MIN(ctid) as ctid, name, surname
FROM people 
GROUP BY (name, surname) HAVING COUNT(*) > 1;


DELETE FROM people a USING (
    SELECT MIN(ctid) as ctid, name, surname
    FROM people 
    GROUP BY (name, surname) HAVING COUNT(*) > 1
) b
WHERE a.name = b.name
AND a.surname = b.surname
AND a.ctid <> b.ctid;

SELECT * FROM people;

内部リクエストの出力は次のようになります。

ctid 名前
(0,1) A. トム

そして、最終的なリクエスト(削除後)の出力は次のようになります。

名前
A. トム 30
B. トム 20
B クリス 20

DB Fiddle でおもちゃの例を見る

おすすめ記事