PostgreSQLでの『ERROR: duplicate key value violates unique constraint』を解決する方法

PostgreSQLでの『ERROR: duplicate key value violates unique constraint』を解決する方法

このエラーは、PostgreSQLでデータを挿入または更新する際に、一意制約(UNIQUE制約)を持つカラムに重複した値を入れようとした場合に発生する。特に主キー(PRIMARY KEY)やユニークインデックスを設定しているテーブルで起こりやすい。この記事では、エラーの原因と具体的な対処法を複数パターンにわけて扱う。

エラーの基本的な発生条件

ERROR: duplicate key value violates unique constraint "your_table_column_key"
DETAIL: Key (column_name)=(duplicate_value) already exists.
  • INSERTやUPDATE時に、UNIQUE制約を持つカラムにすでに存在する値を入れようとした場合
  • シーケンスが意図した値を発行していない場合(主に SERIAL 型や IDENTITY 型)

重複しているレコードの確認方法

SELECT column_name, COUNT(*)
FROM your_table
GROUP BY column_name
HAVING COUNT(*) > 1;

このクエリで、どの値が重複しているかを特定できる。

UNIQUE制約を持つカラムの確認方法

SELECT indexname, indexdef
FROM pg_indexes
WHERE tablename = 'your_table';

UNIQUE が含まれている定義を探すことで、どのカラムに制約があるかを知ることができる。

シーケンスがずれている場合の修正

特に SERIAL 型のカラムでは、手動でIDを挿入したり、データのコピーを行った結果、シーケンスと実際の最大IDが一致しないことがある。

SELECT MAX(id) FROM your_table;

その値よりも大きい値にシーケンスをリセットする。

SELECT setval('your_table_id_seq', (SELECT MAX(id) FROM your_table));

INSERT前に重複をチェックする

アプリケーション側でユニーク条件を満たすかを確認してから挿入する方法。

DO $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM your_table WHERE column_name = 'some_value') THEN
        INSERT INTO your_table (column_name) VALUES ('some_value');
    END IF;
END
$$;

ON CONFLICT(UPSERT)構文を使う

PostgreSQL 9.5以降では、重複が発生したときの処理を制御できる。

INSERT INTO your_table (id, name)
VALUES (1, 'Alice')
ON CONFLICT (id) DO NOTHING;

または値を更新する場合:

INSERT INTO your_table (id, name)
VALUES (1, 'Alice')
ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name;

一時的にUNIQUE制約を外す(非推奨)

データのクレンジング時などに制約を一時的に削除して作業することも可能だが、運用データでは避けるべき。

ALTER TABLE your_table DROP CONSTRAINT your_table_column_key;
-- 作業後に再付与
ALTER TABLE your_table ADD CONSTRAINT your_table_column_key UNIQUE (column_name);

重複データの削除方法

重複しているデータを削除するクエリの一例。

DELETE FROM your_table
WHERE id NOT IN (
  SELECT MIN(id)
  FROM your_table
  GROUP BY column_name
);

トランザクションと同時実行の影響

同時に複数のプロセスが同じデータを挿入しようとすると、意図せず重複が起こることがある。排他制御(例:FOR UPDATE)や適切なトランザクション制御が重要。

重複の原因になりやすいデータインポート

CSVや他のDBからのデータ移行時に、主キーやユニークなカラムの衝突が発生するケースがある。インポート前に以下のようなチェックを行う。

SELECT * FROM your_table
WHERE id IN (SELECT id FROM staging_table);

一意制約が複数カラムで構成されている場合

複合ユニーク制約(複数カラムに対するUNIQUE制約)が原因のこともある。

ALTER TABLE your_table ADD CONSTRAINT unique_multi_col UNIQUE (col1, col2);

この場合、どの組み合わせが重複しているかを確認する必要がある。

SELECT col1, col2, COUNT(*)
FROM your_table
GROUP BY col1, col2
HAVING COUNT(*) > 1;

まとめ

  • PostgreSQLの「duplicate key value」エラーはUNIQUE制約違反
  • シーケンスずれ、重複インポート、トランザクション競合が主な原因
  • ON CONFLICTsetval() の活用で多くのケースを安全に処理可能