Corriger PG::UniqueViolation quand il n'y a pas de violation unique

Avez-vous déjà rencontré une erreur PG::UniqueViolation alors que vous êtes certain qu’il n’y a pas de données en double ? Le coupable est souvent une séquence PostgreSQL désynchronisée.

Le Problème

Vous voyez une erreur comme :

PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "users_pkey"
DETAIL: Key (id)=(42) already exists.

Mais quand vous vérifiez, il n’y a aucun enregistrement avec l’ID 42. Que se passe-t-il ?

La Cause

PostgreSQL utilise des séquences pour générer des IDs auto-incrémentés. Parfois, surtout après des importations de données ou des insertions manuelles, la séquence se désynchronise avec l’ID maximum réel dans la table.

La Solution

Réinitialisez la séquence à la valeur correcte :

SELECT setval('users_id_seq', (SELECT MAX(id) FROM users));

Ou en Rails :

ActiveRecord::Base.connection.execute(
  "SELECT setval('users_id_seq', (SELECT MAX(id) FROM users))"
)

Pour Toutes les Tables

Pour corriger toutes les séquences en une fois :

ActiveRecord::Base.connection.tables.each do |table|
  ActiveRecord::Base.connection.reset_pk_sequence!(table)
end

Prévention

Ce problème survient couramment après :

  • Des migrations ou importations de données
  • Des insertions SQL manuelles avec des IDs explicites
  • La restauration depuis des sauvegardes

Réinitialisez toujours les séquences après des opérations de données en masse pour éviter ces erreurs mystérieuses.