Corrigiendo PG::UniqueViolation cuando no hay violación única

¿Alguna vez has encontrado un error PG::UniqueViolation cuando estás seguro de que no hay datos duplicados? El culpable suele ser una secuencia de PostgreSQL que está desincronizada.

El Problema

Ves un error como:

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

Pero cuando verificas, no hay ningún registro con ID 42. ¿Qué está pasando?

La Causa

PostgreSQL usa secuencias para generar IDs auto-incrementales. A veces, especialmente después de importaciones de datos o inserciones manuales, la secuencia se desincroniza con el ID máximo real en la tabla.

La Solución

Restablece la secuencia al valor correcto:

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

O en Rails:

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

Para Todas las Tablas

Para corregir todas las secuencias a la vez:

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

Prevención

Este problema ocurre comúnmente después de:

  • Migraciones o importaciones de datos
  • Inserciones SQL manuales con IDs explícitos
  • Restauración desde backups

Siempre restablece las secuencias después de operaciones masivas de datos para evitar estos errores misteriosos.