一意制約違反がないのにPG::UniqueViolationを修正する方法
重複データがないことが確実なのにPG::UniqueViolationエラーに遭遇したことはありませんか?原因は多くの場合、同期が外れたPostgreSQLシーケンスです。
問題
次のようなエラーが表示されます:
PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "users_pkey"
DETAIL: Key (id)=(42) already exists.
しかし確認すると、ID 42のレコードは存在しません。何が起きているのでしょうか?
原因
PostgreSQLはシーケンスを使用して自動増分IDを生成します。時々、特にデータのインポートや手動での挿入の後、シーケンスがテーブル内の実際の最大IDと同期が外れることがあります。
修正方法
シーケンスを正しい値にリセットします:
SELECT setval('users_id_seq', (SELECT MAX(id) FROM users));
またはRailsで:
ActiveRecord::Base.connection.execute(
"SELECT setval('users_id_seq', (SELECT MAX(id) FROM users))"
)
すべてのテーブルに対して
すべてのシーケンスを一度に修正するには:
ActiveRecord::Base.connection.tables.each do |table|
ActiveRecord::Base.connection.reset_pk_sequence!(table)
end
予防
この問題は一般的に以下の後に発生します:
- データの移行またはインポート
- 明示的なIDを使用した手動SQLの挿入
- バックアップからの復元
これらの不思議なエラーを避けるために、大量データ操作の後は常にシーケンスをリセットしてください。