Me encontré con el problema de que mi secuencia de teclas principal no está sincronizada con las filas de mi tabla.
Es decir, cuando inserto una nueva fila obtengo un error de clave duplicada porque la secuencia implícita en el tipo de datos en serie devuelve un número que ya existe.
Parece ser causado por la importación / restauración que no mantiene la secuencia correctamente.
postgresql
primary-key
database-sequence
melancólico
fuente
fuente
Respuestas:
Fuente - Ruby Forum
fuente
SELECT setval('your_table_id_seq', coalesce((select max(id)+1 from your_table), 1), false);
SELECT setval('your_seq',(SELECT GREATEST(MAX(your_id)+1,nextval('your_seq'))-1 FROM your_table))
pg_get_serial_sequence
se puede usar para evitar suposiciones incorrectas sobre el nombre de la secuencia. Esto restablece la secuencia en una sola toma:O más concisamente:
Sin embargo, este formulario no puede manejar tablas vacías correctamente, ya que max (id) es nulo, y tampoco puede establecer el valor 0 porque estaría fuera del rango de la secuencia. Una solución para esto es recurrir a la
ALTER SEQUENCE
sintaxis, es decirPero
ALTER SEQUENCE
es de uso limitado porque el nombre de secuencia y el valor de reinicio no pueden ser expresiones.Parece que la mejor solución para todo uso es llamar
setval
a falso como el tercer parámetro, lo que nos permite especificar el "siguiente valor a utilizar":Esto cumple todos mis requisitos:
Finalmente, tenga en cuenta que
pg_get_serial_sequence
solo funciona si la secuencia es propiedad de la columna. Este será el caso si la columna de incremento se definió como unserial
tipo, sin embargo, si la secuencia se agregó manualmente, es necesario asegurarse deALTER SEQUENCE .. OWNED BY
que también se realice.es decir, si
serial
se utilizó el tipo para la creación de la tabla, esto debería funcionar:Pero si las secuencias se agregaron manualmente:
fuente
setval()
establece el valor actual ynextval()
ya devolverá el valor actual +1.La forma más corta y rápida :
tbl_id
siendo laserial
columna de la tablatbl
, dibujando a partir de la secuenciatbl_tbl_id_seq
(que es el nombre automático predeterminado).Si no conoce el nombre de la secuencia adjunta (que no tiene que estar en forma predeterminada), use
pg_get_serial_sequence()
:Aquí no hay ningún error off-by-one. Por documentación:
El énfasis en negrita es mío.
Si la tabla puede estar vacía y comenzar realmente desde 1 en este caso:
No podemos simplemente usar la forma 2-paremater y comenzar
0
porque el límite inferior de las secuencias es 1 por defecto (a menos que esté personalizado).Concurrencia
No hay defensa contra la actividad de secuencia concurrente o escrituras en la tabla en las consultas anteriores, todavía. Si eso es relevante, puede bloquear la tabla en modo exclusivo. Evita que las transacciones simultáneas escriban un número más alto mientras intenta sincronizarse. (También bloquea temporalmente las escrituras inofensivas que no interfieren con el número máximo).
Pero aún no tiene en cuenta a los clientes que pueden haber obtenido números de secuencia por adelantado sin ningún bloqueo en la tabla principal (lo que puede suceder). Para permitir eso, también, solo aumente el valor actual de la secuencia, nunca lo disminuya. Puede parecer paranoico, pero eso está de acuerdo con la naturaleza de las secuencias y la defensa contra los problemas de concurrencia.
fuente
EXECUTE format()
(como @ EB.'s) es una función esencial! ¿Cómo solucionar esta falta de biblioteca estándar en PostgreSQL ????Esto restablecerá todas las secuencias del público sin hacer suposiciones sobre nombres de tablas o columnas. Probado en la versión 8.4
fuente
substring(column_default, '''(.*)''')
lugar detable_name || '_' || column_name || '_seq'
. Funciona perfectamente.quote_literal
yquote_ident
, o preferiblemente laformat
función, realmente deberían usarse aquí.substring(column_default from 'nextval\(''(.+)''::regclass\)')
tomar explícitamente el nombre de la secuencia. Trabajado como un encanto.substring(column_default, '''(.*)''') instead of table_name || '_' || column_name || '_seq'
ALTERAR SECUENCIA secuencia_nombre REINICIAR CON (SELECCIONAR max (id) DE tabla_nombre);No funcionaCopiado de la respuesta @tardate:
fuente
Este comando solo cambia el valor de secuencia de teclas generado automáticamente en postgresql
En lugar de cero, puede poner cualquier número desde el que desea reiniciar la secuencia.
el nombre de secuencia predeterminado lo hará
"TableName_FieldName_seq"
. Por ejemplo, si su nombre de tabla es"MyTable"
y su nombre de campo es"MyID"
, entonces su nombre de secuencia será"MyTable_MyID_seq"
.Esta respuesta es igual a la respuesta de @ murugesanponappan, pero hay un error de sintaxis en su solución. no puedes usar subconsulta
(select max()...)
en elalter
comando. Para que tenga que usar un valor numérico fijo o necesite usar una variable en lugar de una subconsulta.fuente
Restablezca todas las secuencias, sin suposiciones sobre nombres, excepto que la clave principal de cada tabla es "id":
fuente
pg_get_serial_sequence(''"' || tablename || '"''
EXECUTE format( 'SELECT setval(pg_get_serial_sequence(%L, %L), coalesce(max(id),0) + 1, false) FROM %I;', $1,$2,$1 );
Estas funciones están llenas de peligros cuando los nombres de secuencia, nombres de columna, nombres de tabla o nombres de esquema tienen caracteres divertidos como espacios, signos de puntuación y similares. He escrito esto:
Puede llamarlo para una sola secuencia pasándole el OID y devolverá el número más alto utilizado por cualquier tabla que tenga la secuencia por defecto; o puede ejecutarlo con una consulta como esta, para restablecer todas las secuencias en su base de datos:
Usando una calidad diferente, puede restablecer solo la secuencia en un determinado esquema, y así sucesivamente. Por ejemplo, si desea ajustar secuencias en el esquema "público":
Tenga en cuenta que debido a cómo funciona setval (), no necesita agregar 1 al resultado.
Como nota final, tengo que advertir que algunas bases de datos parecen tener valores predeterminados que se vinculan a secuencias de manera que no permiten que los catálogos del sistema tengan información completa sobre ellas. Esto sucede cuando ves cosas como esta en psql's \ d:
Tenga en cuenta que la llamada nextval () en esa cláusula predeterminada tiene una conversión :: text además de la conversión :: regclass. Creo que esto se debe a que las bases de datos se pg_dump'ed de versiones anteriores de PostgreSQL. Lo que sucederá es que la función secuencia_max_valor () anterior ignorará dicha tabla. Para solucionar el problema, puede redefinir la cláusula DEFAULT para referirse a la secuencia directamente sin el reparto:
Entonces psql lo muestra correctamente:
Tan pronto como haya solucionado eso, la función funciona correctamente para esta tabla, así como para todas las demás que podrían usar la misma secuencia.
fuente
newmax := r.max::bigint;
para que funcione correctamente para mí.'SELECT max(' || quote_ident(colname) || ') FROM '
=>'SELECT max(' || quote_ident(colname) || '::bigint) FROM '
observe la conversión agregada::bigint
dentro de la consulta de compilación dinámica.Otro plpgsql: se restablece solo si
max(att) > then lastval
también comentar la línea
--execute format('alter sequence
dará la lista, en realidad no restablecerá el valorfuente
Restablecer toda la secuencia de public
fuente
Sugiero que esta solución se encuentre en postgres wiki. Actualiza todas las secuencias de tus tablas.
Cómo usar (de postgres wiki):
Ejemplo:
Artículo original (también con arreglo para propiedad de secuencia) aquí
fuente
Algunas respuestas realmente difíciles aquí, supongo que solía ser realmente malo en el momento en que esto se ha preguntado, ya que muchas respuestas de aquí no funcionan para la versión 9.3. La documentación desde la versión 8.0 proporciona una respuesta a esta misma pregunta:
Además, si necesita cuidar los nombres de secuencia que distinguen entre mayúsculas y minúsculas, así es como lo hace:
fuente
Este problema ocurre conmigo cuando uso el marco de entidad para crear la base de datos y luego sembrar la base de datos con datos iniciales, esto hace que la secuencia no coincida.
Lo resolví creando un script para ejecutar después de sembrar la base de datos:
fuente
MAX("Id") + 1
funciona mejor para mí cuando la secuencia es = al máximo.Mi versión usa la primera, con algunos errores de comprobación ...
fuente
RAISE WARNING
identificó.Poniendolo todo junto
fijará la
id'
secuencia de la tabla dada (como suele ser necesario con django, por ejemplo).fuente
antes aún no había probado el código: a continuación publico la versión para el código sql para las soluciones Klaus y user457226 que funcionaban en mi PC [Postgres 8.3], con solo algunos pequeños ajustes para el Klaus y para mi versión para el usuario457226 uno.
Solución de Klaus:
Solución user457226:
fuente
Vuelva a verificar toda la secuencia en la función de esquema público
fuente
Para reiniciar toda la secuencia a 1 use:
fuente
La respuesta de Klaus es la más útil, a excepción de un pequeño error: debe agregar DISTINCT en la instrucción select.
Sin embargo, si está seguro de que ningún nombre de tabla + columna puede ser equivalente para dos tablas diferentes, también puede usar:
que es una extensión de la solución user457226 para el caso en que el nombre de una columna interesada no es 'ID'.
fuente
Si ve este error cuando está cargando datos SQL personalizados para la inicialización, otra forma de evitar esto es:
En lugar de escribir:
Eliminar la
id
(clave principal) de los datos iniciales¡Esto mantiene la secuencia de Postgres sincronizada!
fuente
Esta respuesta es una copia de mauro.
fuente
Pasé una hora tratando de obtener la respuesta de djsnowsill para trabajar con una base de datos usando tablas y columnas de casos mixtos, luego finalmente me topé con la solución gracias a un comentario de Manuel Darveau, pero pensé que podría aclararlo un poco a todos:
Esto tiene el beneficio de:
Para explicarlo, el problema era que
pg_get_serial_sequence
tomaba medidas para resolver a qué se refería, así que si lo hace:Esto se logra usando
''%1$I''
la cadena de formato,''
hace que un apóstrofe1$
signifique el primer argumento y lasI
comillas.fuente
fuente
Hack feo para arreglarlo usando un poco de magia de shell, no es una gran solución, pero podría inspirar a otros con problemas similares :)
fuente
Prueba reindexar .
ACTUALIZACIÓN: Como se señaló en los comentarios, esto fue en respuesta a la pregunta original.
fuente
SELECT setval...
hace JDBC bork, así que aquí hay una forma compatible con Java de hacer esto:fuente
Un método para actualizar todas las secuencias en su esquema que se utilizan como ID:
fuente
Simplemente ejecute debajo del comando:
fuente
Hay muchas buenas respuestas aquí. Tenía la misma necesidad después de volver a cargar mi base de datos Django.
Pero yo necesitaba:
Esto parece una necesidad muy similar a lo que fue la solicitud original.
Gracias a Baldiry y Mauro me pusieron en el camino correcto.
Luego, para ejecutar y ver los cambios ejecutados:
Devoluciones
fuente