postgresql - setval - ¿Cómo restablecer la secuencia de clave principal de Postgres cuando no está sincronizada?
set sequence id postgres (25)
Algunas respuestas realmente graves aquí, supongo que solían ser muy malas en el momento en que se ha pedido esto, ya que muchas respuestas de aquí no funcionan para la versión 9.3. La documentation desde la versión 8.0 proporciona una respuesta a esta pregunta:
SELECT setval(''serial'', max(id)) FROM distributors;
Además, si necesita ocuparse de los nombres de secuencia que distinguen entre mayúsculas y minúsculas, así es como lo hace:
SELECT setval(''"Serial"'', max(id)) FROM distributors;
Me encontré con el problema de que mi secuencia de clave principal no está sincronizada con las filas de la tabla.
Es decir, cuando inserto una nueva fila, aparece 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.
El camino más corto y rápido :
SELECT setval(''tbl_tbl_id_seq'', max(tbl_id)) FROM tbl;
tbl_id
es la columna en serial
de la tabla tbl
, que se extrae de la secuencia tbl_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()
:
SELECT setval(pg_get_serial_sequence(''tbl'', ''tbl_id''), max(tbl_id)) FROM tbl;
No hay error off-by-one aquí. Por documentación:
La forma de dos parámetros establece el último campo de valor de la secuencia en el valor especificado y establece su campo
is_called
en verdadero, lo que significa que el siguiente próximonextval
avanzará la secuencia antes de devolver un valor.
Énfasis en negrita el mio
Concurrencia
No hay defensa contra la actividad de secuencia concurrente o las 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 mayor mientras intenta sincronizarse. (También bloquea temporalmente las escrituras inofensivas sin alterar el número máximo).
Pero no tiene en cuenta a los clientes que pueden haber obtenido números de secuencia de antemano sin ningún bloqueo en la tabla principal (lo que puede suceder). Para permitir eso, también, solo aumentar el valor actual de la secuencia, nunca disminuirlo. Puede parecer paranoico, pero está de acuerdo con la naturaleza de las secuencias y la defensa contra los problemas de concurrencia.
BEGIN;
LOCK TABLE tbl IN EXCLUSIVE MODE;
SELECT setval(''tbl_tbl_id_seq'', max(tbl_id))
FROM tbl
HAVING max(tbl_id) > (SELECT last_value FROM tbl_tbl_id_seq);
COMMIT;
Esta respuesta es una copia de mauro.
drop function IF EXISTS rebuilt_sequences() RESTRICT;
CREATE OR REPLACE FUNCTION rebuilt_sequences() RETURNS integer as
$body$
DECLARE sequencedefs RECORD; c integer ;
BEGIN
FOR sequencedefs IN Select
DISTINCT(constraint_column_usage.table_name) as tablename,
constraint_column_usage.column_name as columnname,
replace(replace(columns.column_default,''''''::regclass)'',''''),''nextval('''''','''') as sequencename
from information_schema.constraint_column_usage, information_schema.columns
where constraint_column_usage.table_schema =''public'' AND
columns.table_schema = ''public'' AND columns.table_name=constraint_column_usage.table_name
AND constraint_column_usage.column_name = columns.column_name
AND columns.column_default is not null
ORDER BY sequencename
LOOP
EXECUTE ''select max(''||sequencedefs.columnname||'') from '' || sequencedefs.tablename INTO c;
IF c is null THEN c = 0; END IF;
IF c is not null THEN c = c+ 1; END IF;
EXECUTE ''alter sequence '' || sequencedefs.sequencename ||'' minvalue ''||c ||'' start '' || c ||'' restart with '' || c;
END LOOP;
RETURN 1; END;
$body$ LANGUAGE plpgsql;
select rebuilt_sequences();
Estas funciones están plagadas de peligros cuando los nombres de secuencia, nombres de columnas, nombres de tablas o nombres de esquemas tienen caracteres divertidos, como espacios, signos de puntuación y similares. He escrito esto:
CREATE OR REPLACE FUNCTION sequence_max_value(oid) RETURNS bigint
VOLATILE STRICT LANGUAGE plpgsql AS $$
DECLARE
tabrelid oid;
colname name;
r record;
newmax bigint;
BEGIN
FOR tabrelid, colname IN SELECT attrelid, attname
FROM pg_attribute
WHERE (attrelid, attnum) IN (
SELECT adrelid::regclass,adnum
FROM pg_attrdef
WHERE oid IN (SELECT objid
FROM pg_depend
WHERE refobjid = $1
AND classid = ''pg_attrdef''::regclass
)
) LOOP
FOR r IN EXECUTE ''SELECT max('' || quote_ident(colname) || '') FROM '' || tabrelid::regclass LOOP
IF newmax IS NULL OR r.max > newmax THEN
newmax := r.max;
END IF;
END LOOP;
END LOOP;
RETURN newmax;
END; $$ ;
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 como predeterminada; o puede ejecutarlo con una consulta como esta, para restablecer todas las secuencias en su base de datos:
select relname, setval(oid, sequence_max_value(oid))
from pg_class
where relkind = ''S'';
Usando una calificación diferente, puede restablecer solo la secuencia en un determinado esquema, y así sucesivamente. Por ejemplo, si desea ajustar secuencias en el esquema "público":
select relname, setval(pg_class.oid, sequence_max_value(pg_class.oid))
from pg_class, pg_namespace
where pg_class.relnamespace = pg_namespace.oid and
nspname = ''public'' and
relkind = ''S'';
Tenga en cuenta que debido a cómo funciona setval (), no necesita agregar 1 al resultado.
Como nota final, debo 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:
alvherre=# /d baz
Tabla «public.baz»
Columna | Tipo | Modificadores
---------+---------+------------------------------------------------
a | integer | default nextval((''foo_a_seq''::text)::regclass)
Tenga en cuenta que la llamada nextval () en esa cláusula predeterminada tiene una conversión de texto :: además de la conversión :: regclass. Creo que esto se debe a que las bases de datos son pg_dump''ed de versiones anteriores de PostgreSQL. Lo que sucederá es que la función sequence_max_value () anterior ignorará dicha tabla. Para solucionar el problema, puede redefinir la cláusula DEFAULT para referirse a la secuencia directamente sin la conversión:
alvherre=# alter table baz alter a set default nextval(''foo_a_seq'');
ALTER TABLE
Entonces psql lo muestra correctamente:
alvherre=# /d baz
Tabla «public.baz»
Columna | Tipo | Modificadores
---------+---------+----------------------------------------
a | integer | default nextval(''foo_a_seq''::regclass)
Tan pronto como lo hayas solucionado, la función funciona correctamente para esta tabla, así como para todas las demás que podrían usar la misma secuencia.
Este comando solo cambia el valor de la secuencia de la clave generada automáticamente en postgresql
ALTER SEQUENCE "your_sequence_name" RESTART WITH 0;
En lugar de cero, puede poner cualquier número desde el que desee reiniciar la secuencia.
el nombre de secuencia predeterminado será "TableName_FieldName_seq"
. Por ejemplo, si el nombre de su tabla es "MyTable"
y su nombre de campo es "MyID"
, entonces su nombre de secuencia será "MyTable_MyID_seq"
.
Esta respuesta es la misma que la respuesta de @ murugesanponappan, pero hay un error de sintaxis en su solución. no puede usar la sub consulta (select max()...)
en el comando de alter
. Para que tenga que usar un valor numérico fijo o una variable en lugar de una sub consulta.
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 ejecutarlo después de sembrar la base de datos:
DO
$do$
DECLARE tablename text;
BEGIN
-- change the where statments to include or exclude whatever tables you need
FOR tablename IN SELECT table_name FROM information_schema.tables WHERE table_schema=''public'' AND table_type=''BASE TABLE'' AND table_name != ''__EFMigrationsHistory''
LOOP
EXECUTE format(''SELECT setval(pg_get_serial_sequence(''''"%s"'''', ''''Id''''), (SELECT MAX("Id") + 1 from "%s"))'', tablename, tablename);
END LOOP;
END
$do$
Esto restablecerá todas las secuencias del público sin hacer suposiciones sobre los nombres de tablas o columnas. Probado en la versión 8.4
CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text, columnname text, sequence_name text) RETURNS "pg_catalog"."void" AS
$body$
DECLARE
BEGIN
EXECUTE ''SELECT setval( '''''' || sequence_name || '''''', '' || ''(SELECT MAX('' || columnname || '') FROM '' || tablename || '')'' || ''+1)'';
END;
$body$ LANGUAGE ''plpgsql'';
select table_name || ''_'' || column_name || ''_seq'', reset_sequence(table_name, column_name, table_name || ''_'' || column_name || ''_seq'') from information_schema.columns where column_default like ''nextval%'';
Intenta reindex .
ACTUALIZACIÓN: Como se señaló en los comentarios, esto fue en respuesta a la pregunta original.
La respuesta de Klaus es la más útil, excepto para un poco de error: tiene que agregar DISTINCT en la declaración de selección.
Sin embargo, si está seguro de que ningún nombre de tabla + columna puede ser equivalente para dos tablas diferentes, también puede usar:
select sequence_name, --PG_CLASS.relname, PG_ATTRIBUTE.attname
reset_sequence(split_part(sequence_name, ''_id_seq'',1))
from PG_CLASS
join PG_ATTRIBUTE on PG_ATTRIBUTE.attrelid = PG_CLASS.oid
join information_schema.sequences
on information_schema.sequences.sequence_name = PG_CLASS.relname || ''_'' || PG_ATTRIBUTE.attname
where sequence_schema=''public'';
que es una extensión de la solución user457226 para el caso en que algún nombre de columna interesada no sea ''ID''.
Mi versión usa la primera, con algún error de comprobación ...
BEGIN;
CREATE OR REPLACE FUNCTION reset_sequence(_table_schema text, _tablename text, _columnname text, _sequence_name text)
RETURNS pg_catalog.void AS
$BODY$
DECLARE
BEGIN
PERFORM 1
FROM information_schema.sequences
WHERE
sequence_schema = _table_schema AND
sequence_name = _sequence_name;
IF FOUND THEN
EXECUTE ''SELECT setval( '''''' || _table_schema || ''.'' || _sequence_name || '''''', '' || ''(SELECT MAX('' || _columnname || '') FROM '' || _table_schema || ''.'' || _tablename || '')'' || ''+1)'';
ELSE
RAISE WARNING ''SEQUENCE NOT UPDATED ON %.%'', _tablename, _columnname;
END IF;
END;
$BODY$
LANGUAGE ''plpgsql'';
SELECT reset_sequence(table_schema, table_name, column_name, table_name || ''_'' || column_name || ''_seq'')
FROM information_schema.columns
WHERE column_default LIKE ''nextval%'';
DROP FUNCTION reset_sequence(_table_schema text, _tablename text, _columnname text, _sequence_name text) ;
COMMIT;
Para reiniciar toda la secuencia a 1 use:
-- Create Function
CREATE OR REPLACE FUNCTION "sy_restart_seq_to_1" (
relname TEXT
)
RETURNS "pg_catalog"."void" AS
$BODY$
DECLARE
BEGIN
EXECUTE ''ALTER SEQUENCE ''||relname||'' RESTART WITH 1;'';
END;
$BODY$
LANGUAGE ''plpgsql'';
-- Use Function
SELECT
relname
,sy_restart_seq_to_1(relname)
FROM pg_class
WHERE relkind = ''S'';
Pasé una hora tratando de obtener la respuesta de djsnowsill para trabajar con una base de datos utilizando tablas y columnas de Casos Mixtos, luego finalmente encontré la solución gracias a un comentario de Manuel Darveau, pero pensé que podía aclararlo un poco para todos:
CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text, columnname text)
RETURNS "pg_catalog"."void" AS
$body$
DECLARE
BEGIN
EXECUTE format(''SELECT setval(pg_get_serial_sequence(''''%1$I'''', %2$L),
(SELECT COALESCE(MAX(%2$I)+1,1) FROM %1$I), false)'',tablename,columnname);
END;
$body$ LANGUAGE ''plpgsql'';
SELECT format(''%s_%s_seq'',table_name,column_name), reset_sequence(table_name,column_name)
FROM information_schema.columns WHERE column_default like ''nextval%'';
Esto tiene el beneficio de:
- no asumiendo que la columna de ID se escribe de una manera particular.
- No asumiendo que todas las tablas tienen una secuencia.
- trabajando para nombres de tablas / columnas de casos mixtos.
- Usando el formato para ser más conciso.
Para explicarlo, el problema fue que pg_get_serial_sequence
toma cadenas para resolver a qué se refiere, por lo que si lo hace:
"TableName" --it thinks it''s a table or column
''TableName'' --it thinks it''s a string, but makes it lower case
''"TableName"'' --it works!
Esto se logra usando ''''%1$I''''
en la cadena de formato, ''''
hace que un apóstrofe 1$
signifique primero arg, y I
decir entre comillas
Poniendolo todo junto
CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text)
RETURNS "pg_catalog"."void" AS
$body$
DECLARE
BEGIN
EXECUTE ''SELECT setval( pg_get_serial_sequence('''''' || tablename || '''''', ''''id''''),
(SELECT COALESCE(MAX(id)+1,1) FROM '' || tablename || ''), false)'';
END;
$body$ LANGUAGE ''plpgsql'';
id''
secuencia de '' id''
de la tabla dada (como suele ser necesario con django, por ejemplo).
Restablecer todas las secuencias de público
CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text) RETURNS "pg_catalog"."void" AS
$body$
DECLARE
BEGIN
EXECUTE ''SELECT setval( ''''''
|| tablename
|| ''_id_seq'''', ''
|| ''(SELECT id + 1 FROM "''
|| tablename
|| ''" ORDER BY id DESC LIMIT 1), false)'';
END;
$body$ LANGUAGE ''plpgsql'';
select sequence_name, reset_sequence(split_part(sequence_name, ''_id_seq'',1)) from information_schema.sequences
where sequence_schema=''public'';
Restablecer todas las secuencias, no hay suposiciones sobre los nombres, excepto que la clave principal de cada tabla es "id":
CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text, columnname text)
RETURNS "pg_catalog"."void" AS
$body$
DECLARE
BEGIN
EXECUTE ''SELECT setval( pg_get_serial_sequence('''''' || tablename || '''''', '''''' || columnname || ''''''),
(SELECT COALESCE(MAX(id)+1,1) FROM '' || tablename || ''), false)'';
END;
$body$ LANGUAGE ''plpgsql'';
select table_name || ''_'' || column_name || ''_seq'', reset_sequence(table_name, column_name) from information_schema.columns where column_default like ''nextval%'';
Si ve este error cuando está cargando datos SQL personalizados para la inicialización, otra forma de evitar esto es:
En lugar de escribir:
INSERT INTO book (id, name, price) VALUES (1 , ''Alchemist'' , 10),
Eliminar el id
(clave principal) de los datos iniciales
INSERT INTO book (name, price) VALUES (''Alchemist'' , 10),
Esto mantiene sincronizada la secuencia de Postgres!
Sin embargo, otro plpgsql - se reinicia solo si max(att) > then lastval
do --check seq not in sync
$$
declare
_r record;
_i bigint;
_m bigint;
begin
for _r in (
SELECT relname,nspname,d.refobjid::regclass, a.attname, refobjid
FROM pg_depend d
JOIN pg_attribute a ON a.attrelid = d.refobjid AND a.attnum = d.refobjsubid
JOIN pg_class r on r.oid = objid
JOIN pg_namespace n on n.oid = relnamespace
WHERE d.refobjsubid > 0 and relkind = ''S''
) loop
execute format(''select last_value from %I.%I'',_r.nspname,_r.relname) into _i;
execute format(''select max(%I) from %s'',_r.attname,_r.refobjid) into _m;
if coalesce(_m,0) > _i then
raise info ''%'',concat(''changed: '',_r.nspname,''.'',_r.relname,'' from:'',_i,'' to:'',_m);
execute format(''alter sequence %I.%I restart with %s'',_r.nspname,_r.relname,_m+1);
end if;
end loop;
end;
$$
;
también comentando la línea --execute format(''alter sequence
dará la lista, no restableciendo realmente el valor
Sugiero esta solución encontrada en postgres wiki. Actualiza todas las secuencias de tus tablas.
SELECT ''SELECT SETVAL('' ||
quote_literal(quote_ident(PGT.schemaname) || ''.'' || quote_ident(S.relname)) ||
'', COALESCE(MAX('' ||quote_ident(C.attname)|| ''), 1) ) FROM '' ||
quote_ident(PGT.schemaname)|| ''.''||quote_ident(T.relname)|| '';''
FROM pg_class AS S,
pg_depend AS D,
pg_class AS T,
pg_attribute AS C,
pg_tables AS PGT
WHERE S.relkind = ''S''
AND S.oid = D.objid
AND D.refobjid = T.oid
AND D.refobjid = C.attrelid
AND D.refobjsubid = C.attnum
AND T.relname = PGT.tablename
ORDER BY S.relname;
Cómo utilizar (desde postgres wiki):
- Guarda esto en un archivo, di ''reset.sql''
- Ejecute el archivo y guarde su salida de una manera que no incluya los encabezados habituales, luego ejecute esa salida. Ejemplo:
Ejemplo:
psql -Atq -f reset.sql -o temp
psql -f temp
rm temp
Artículo original (también con arreglo para la propiedad de secuencia) here
Un truco feo para arreglarlo usando algo de magia de shell, no es una gran solución pero podría inspirar a otros con problemas similares :)
pg_dump -s <DATABASE> | grep ''CREATE TABLE'' | awk ''{print "SELECT setval(#" $3 "_id_seq#, (SELECT MAX(id) FROM " $3 "));"}'' | sed "s/#/''/g" | psql <DATABASE> -f -
Vuelva a comprobar todas las secuencias en la función de esquema público
CREATE OR REPLACE FUNCTION public.recheck_sequence (
)
RETURNS void AS
$body$
DECLARE
_table_name VARCHAR;
_column_name VARCHAR;
_sequence_name VARCHAR;
BEGIN
FOR _table_name IN SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = ''public'' LOOP
FOR _column_name IN SELECT column_name FROM information_schema.columns WHERE table_name = _table_name LOOP
SELECT pg_get_serial_sequence(_table_name, _column_name) INTO _sequence_name;
IF _sequence_name IS NOT NULL THEN
EXECUTE ''SELECT setval(''''''||_sequence_name||'''''', COALESCE((SELECT MAX(''||quote_ident(_column_name)||'')+1 FROM ''||quote_ident(_table_name)||''), 1), FALSE);'';
END IF;
END LOOP;
END LOOP;
END;
$body$
LANGUAGE ''plpgsql''
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100;
antes no había probado todavía el código: a continuación publico la versión para el código sql para las soluciones Klaus y user457226 que funcionaron en mi PC [Postgres 8.3], con solo algunos pequeños ajustes para el Klaus uno y de mi versión para el usuario 457226 uno.
Solución de Klaus:
drop function IF EXISTS rebuilt_sequences() RESTRICT;
CREATE OR REPLACE FUNCTION rebuilt_sequences() RETURNS integer as
$body$
DECLARE sequencedefs RECORD; c integer ;
BEGIN
FOR sequencedefs IN Select
constraint_column_usage.table_name as tablename,
constraint_column_usage.table_name as tablename,
constraint_column_usage.column_name as columnname,
replace(replace(columns.column_default,''''''::regclass)'',''''),''nextval('''''','''') as sequencename
from information_schema.constraint_column_usage, information_schema.columns
where constraint_column_usage.table_schema =''public'' AND
columns.table_schema = ''public'' AND columns.table_name=constraint_column_usage.table_name
AND constraint_column_usage.column_name = columns.column_name
AND columns.column_default is not null
LOOP
EXECUTE ''select max(''||sequencedefs.columnname||'') from '' || sequencedefs.tablename INTO c;
IF c is null THEN c = 0; END IF;
IF c is not null THEN c = c+ 1; END IF;
EXECUTE ''alter sequence '' || sequencedefs.sequencename ||'' restart with '' || c;
END LOOP;
RETURN 1; END;
$body$ LANGUAGE plpgsql;
select rebuilt_sequences();
solución user457226:
--drop function IF EXISTS reset_sequence (text,text) RESTRICT;
CREATE OR REPLACE FUNCTION "reset_sequence" (tablename text,columnname text) RETURNS bigint --"pg_catalog"."void"
AS
$body$
DECLARE seqname character varying;
c integer;
BEGIN
select tablename || ''_'' || columnname || ''_seq'' into seqname;
EXECUTE ''SELECT max("'' || columnname || ''") FROM "'' || tablename || ''"'' into c;
if c is null then c = 0; end if;
c = c+1; --because of substitution of setval with "alter sequence"
--EXECUTE ''SELECT setval( "'' || seqname || ''", '' || cast(c as character varying) || '', false)''; DOES NOT WORK!!!
EXECUTE ''alter sequence '' || seqname ||'' restart with '' || cast(c as character varying);
RETURN nextval(seqname)-1;
END;
$body$ LANGUAGE ''plpgsql'';
select sequence_name, PG_CLASS.relname, PG_ATTRIBUTE.attname,
reset_sequence(PG_CLASS.relname,PG_ATTRIBUTE.attname)
from PG_CLASS
join PG_ATTRIBUTE on PG_ATTRIBUTE.attrelid = PG_CLASS.oid
join information_schema.sequences
on information_schema.sequences.sequence_name = PG_CLASS.relname || ''_'' || PG_ATTRIBUTE.attname || ''_seq''
where sequence_schema=''public'';
pg_get_serial_sequence
se puede utilizar para evitar cualquier suposición incorrecta sobre el nombre de la secuencia. Esto restablece la secuencia en un disparo:
SELECT pg_catalog.setval(pg_get_serial_sequence(''table_name'', ''id''), (SELECT MAX(id) FROM table_name)+1);
O más concisamente:
SELECT pg_catalog.setval(pg_get_serial_sequence(''table_name'', ''id''), MAX(id)) FROM table_name;
Sin embargo, esta forma 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 sintaxis de ALTER SEQUENCE
es decir
ALTER SEQUENCE table_name_id_seq RESTART WITH 1;
ALTER SEQUENCE table_name_id_seq RESTART; -- 8.4 or higher
Pero ALTER SEQUENCE
tiene un uso limitado porque el nombre de secuencia y el valor de reinicio no pueden ser expresiones.
Parece que la mejor solución para todos los propósitos es llamar a setval
con falso como el tercer parámetro, lo que nos permite especificar el "siguiente valor a usar":
SELECT setval(pg_get_serial_sequence(''t1'', ''id''), coalesce(max(id),0) + 1, false) FROM t1;
Esto cumple todos mis casilleros:
- evita codificar el nombre de secuencia real
- maneja las tablas vacías correctamente
- Maneja tablas con datos existentes y no deja un agujero en la secuencia.
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 un tipo de serial
, sin embargo, si la secuencia se agregó manualmente, es necesario asegurarse de que ALTER SEQUENCE .. OWNED BY
también se realiza.
es decir, si se usó serial
tipo de serial
para la creación de tablas, esto debería funcionar:
CREATE TABLE t1 (
id serial,
name varchar(20)
);
SELECT pg_get_serial_sequence(''t1'', ''id''); -- returns ''t1_id_seq''
-- reset the sequence, regardless whether table has rows or not:
SELECT setval(pg_get_serial_sequence(''t1'', ''id''), coalesce(max(id),0) + 1, false) FROM t1;
Pero si las secuencias se agregaran manualmente:
CREATE TABLE t2 (
id integer NOT NULL,
name varchar(20)
);
CREATE SEQUENCE t2_custom_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER TABLE t2 ALTER COLUMN id SET DEFAULT nextval(''t2_custom_id_seq''::regclass);
ALTER SEQUENCE t2_custom_id_seq OWNED BY t2.id; -- required for pg_get_serial_sequence
SELECT pg_get_serial_sequence(''t2'', ''id''); -- returns ''t2_custom_id_seq''
-- reset the sequence, regardless whether table has rows or not:
SELECT setval(pg_get_serial_sequence(''t2'', ''id''), coalesce(max(id),0) + 1, false) FROM t1;
SELECT setval...
hace JDBC bork, así que aquí hay una manera compatible con Java de hacer esto:
-- work around JDBC ''A result was returned when none was expected.''
-- fix broken nextval due to poorly written 20140320100000_CreateAdminUserRoleTables.sql
DO ''BEGIN PERFORM setval(pg_get_serial_sequence(''''admin_user_role_groups'''', ''''id''''), 1 + COALESCE(MAX(id), 0), FALSE) FROM admin_user_role_groups; END;'';
ALTER SEQUENCE sequence_name REINICIAR CON (SELECCIONE max (id) FROM nombre_tabla); No funciona
Copiado de @tardate respuesta:
SELECT setval(pg_get_serial_sequence(''table_name'', ''id''), MAX(id)) FROM table_name;
-- Login to psql and run the following
-- What is the result?
SELECT MAX(id) FROM your_table;
-- Then run...
-- This should be higher than the last result.
SELECT nextval(''your_table_id_seq'');
-- If it''s not higher... run this set the sequence last to your highest id.
-- (wise to run a quick pg_dump first...)
BEGIN;
-- protect against concurrent inserts while you update the counter
LOCK TABLE your_table IN EXCLUSIVE MODE;
-- Update the sequence
SELECT setval(''your_table_id_seq'', COALESCE((SELECT MAX(id)+1 FROM your_table), 1), false);
COMMIT;