既存テーブルへの UNIQUE 制約後付けは適用前に重複を検出する
PostgreSQL
Database
マイグレーション
データが入っているテーブルに UNIQUE 制約(または UNIQUE INDEX)を後から追加するマイグレーションは、既存データに重複があると本番適用時に失敗してデプロイが止まる。ローカル/テスト DB は空なので気づきにくい。
手順
- 適用前に対象キーで重複を検出する読み取り専用クエリを本番で実行する:
SELECT key..., count(*) FROM t GROUP BY key... HAVING count(*) > 1。0件なら安全。該当があれば行(id 群)を確認して統合・削除してから適用する。 - 余剰行数の概算は
sum(cnt - 1)。
型に応じて検出条件を変える
- nullable カラムを含む UNIQUE は、多くの RDB で複数の NULL を重複扱いしない。重複検出では
WHERE col IS NOT NULLで NULL を除外する。 - 関数インデックス(例:
lower(name)の UNIQUE)は、検出も同じ式でグルーピングする(GROUP BY lower(name))。 - ソフトデリート列があるテーブルに「全行対象」の UNIQUE を付けると、削除済み行と現行行の衝突や、削除後の再作成で違反が起きうる。その場合は部分ユニークインデックス(
WHERE deleted_at IS NULL)を検討する。列の有無だけでなく、実際にソフトデリートを使っている(deleted_at を set している)かを確認する。
検証方法
空でない検証用 DB に重複を仕込み、検出クエリが拾うこと、解消後にマイグレーションが通ることを確認する。