serial - setval postgresql
¿Cómo reiniciar la secuencia en postgres y completar la columna de identificación con nuevos datos? (12)
Tengo una mesa con más de millones de filas. Necesito restablecer la secuencia y reasignar la columna de identificación con nuevos valores (1, 2, 3, 4 ... etc ...). ¿Hay alguna manera fácil de hacer eso?
Ambas soluciones proporcionadas no funcionaron para mí;
> SELECT setval(''seq'', 0);
ERROR: setval: value 0 is out of bounds for sequence "seq" (1..9223372036854775807)
setval(''seq'', 1)
comienza la numeración con 2, y ALTER SEQUENCE seq START 1
comienza la numeración con 2 también, porque seq.is_llamado es verdadero (Postgres versión 9.0.4)
La solución que funcionó para mí es:
> ALTER SEQUENCE seq RESTART WITH 1;
> UPDATE foo SET id = DEFAULT;
Con PostgreSQL 8.4 o posterior ya no es necesario especificar el WITH 1
. Se usará el valor de inicio que se grabó mediante CREATE SEQUENCE
o el último establecido por ALTER SEQUENCE START WITH
(lo más probable es que sea 1).
Restablece la secuencia:
ALTER SEQUENCE seq RESTART;
Luego actualice la columna de ID de la tabla:
UPDATE foo SET id = DEFAULT;
Fuente: Documentos de PostgreSQL
En mi caso, logré esto con:
ALTER SEQUENCE table_tabl_id_seq RESTART WITH 6;
Donde mi tabla se llama tabla
FYI: si necesita especificar un nuevo valor de inicio entre un rango de ID (256 - 10000000 por ejemplo):
SELECT setval(''"Sequence_Name"'',
(SELECT coalesce(MAX("ID"),255)
FROM "Table_Name"
WHERE "ID" < 10000000 and "ID" >= 256)+1
);
Inspirado por las otras respuestas aquí, creé una función SQL para hacer una migración de secuencia. La función mueve una secuencia de tecla primaria a una nueva secuencia contigua comenzando con cualquier valor (> = 1) dentro o fuera del rango de secuencia existente.
Explico here cómo utilicé esta función en una migración de dos bases de datos con el mismo esquema pero diferentes valores en una base de datos.
Primero, la función (que imprime los comandos SQL generados para que quede claro lo que está sucediendo realmente):
CREATE OR REPLACE FUNCTION migrate_pkey_sequence
( arg_table text
, arg_column text
, arg_sequence text
, arg_next_value bigint -- Must be >= 1
)
RETURNS int AS $$
DECLARE
result int;
curr_value bigint = arg_next_value - 1;
update_column1 text := format
( ''UPDATE %I SET %I = nextval(%L) + %s''
, arg_table
, arg_column
, arg_sequence
, curr_value
);
alter_sequence text := format
( ''ALTER SEQUENCE %I RESTART WITH %s''
, arg_sequence
, arg_next_value
);
update_column2 text := format
( ''UPDATE %I SET %I = DEFAULT''
, arg_table
, arg_column
);
select_max_column text := format
( ''SELECT coalesce(max(%I), %s) + 1 AS nextval FROM %I''
, arg_column
, curr_value
, arg_table
);
BEGIN
-- Print the SQL command before executing it.
RAISE INFO ''%'', update_column1;
EXECUTE update_column1;
RAISE INFO ''%'', alter_sequence;
EXECUTE alter_sequence;
RAISE INFO ''%'', update_column2;
EXECUTE update_column2;
EXECUTE select_max_column INTO result;
RETURN result;
END $$ LANGUAGE plpgsql;
La función migrate_pkey_sequence
toma los siguientes argumentos:
-
arg_table
: nombre de la tabla (por''example''
) -
arg_column
: nombre de la columna de la clave principal (por ejemplo,''id''
) -
arg_sequence
: nombre de la secuencia (por ejemplo,''example_id_seq''
) -
arg_next_value
: siguiente valor para la columna después de la migración
Realiza las siguientes operaciones:
- Mueva los valores de la clave primaria a un rango libre. Supongo que
nextval(''example_id_seq'')
sigue amax(id)
y que la secuencia comienza con 1. Esto también maneja el caso dondearg_next_value > max(id)
. - Mueva los valores de la clave primaria al rango contiguo comenzando con
arg_next_value
. El orden de los valores clave se conserva, pero los agujeros en el rango no se conservan. - Imprime el siguiente valor que seguiría en la secuencia. Esto es útil si desea migrar las columnas de otra tabla y combinarlas con esta.
Para demostrarlo, usamos una secuencia y tabla definidas de la siguiente manera (por ejemplo, usando psql
):
# CREATE SEQUENCE example_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
# CREATE TABLE example
( id bigint NOT NULL DEFAULT nextval(''example_id_seq''::regclass)
);
Luego, insertamos algunos valores (comenzando, por ejemplo, en 3):
# ALTER SEQUENCE example_id_seq RESTART WITH 3;
# INSERT INTO example VALUES (DEFAULT), (DEFAULT), (DEFAULT);
-- id: 3, 4, 5
Finalmente, example.id
valores de example.id
para comenzar con 1.
# SELECT migrate_pkey_sequence(''example'', ''id'', ''example_id_seq'', 1);
INFO: 00000: UPDATE example SET id = nextval(''example_id_seq'') + 0
INFO: 00000: ALTER SEQUENCE example_id_seq RESTART WITH 1
INFO: 00000: UPDATE example SET id = DEFAULT
migrate_pkey_sequence
-----------------------
4
(1 row)
El resultado:
# SELECT * FROM example;
id
----
1
2
3
(3 rows)
La mejor manera de reiniciar una secuencia para comenzar de nuevo con el número 1 es ejecutar lo siguiente:
ALTER SEQUENCE <tablename>_<id>_seq RESTART WITH 1
Entonces, por ejemplo para la tabla de usuarios sería:
ALTER SEQUENCE users_id_seq RESTART WITH 1
Para mantener el orden de las filas:
UPDATE thetable SET rowid=col_serial FROM
(SELECT rowid, row_number() OVER ( ORDER BY lngid) AS col_serial FROM thetable ORDER BY lngid) AS t1
WHERE thetable.rowid=t1.rowid;
Restablece la secuencia:
SELECT setval(''sequence_name'', 0);
Actualizando registros actuales:
UPDATE foo SET id = DEFAULT;
Si está usando pgAdmin3, expanda ''Secuencias'', haga clic derecho en una secuencia, vaya a ''Propiedades'', y en la pestaña ''Definición'' cambie ''Valor actual'' al valor que desee. No hay necesidad de una consulta.
Si no desea retener el orden de los identificadores, entonces puede
ALTER SEQUENCE seq RESTART WITH 1;
UPDATE t SET idcolumn=nextval(''seq'');
Dudo que haya una manera fácil de hacerlo en el orden que elijas sin volver a crear toda la mesa.
Solo para simplificar y aclarar el uso correcto de ALTER SEQUENCE y SELECT setval para restablecer la secuencia:
ALTER SEQUENCE sequence_name RESTART WITH 1;
es equivalente a
SELECT setval(''sequence_name'', 1, FALSE);
Cualquiera de las declaraciones se puede utilizar para restablecer la secuencia y puede obtener el siguiente valor por nextval (''sequence_name'') como se indica here también:
nextval(''sequence_name'')
Solo restablecer la secuencia y actualizar todas las filas puede causar errores de identificación duplicados. En muchos casos, debe actualizar todas las filas dos veces. Primero con ids más altos para evitar los duplicados, luego con los ID que realmente desea.
Evite agregar una cantidad fija a todos los ID (como se recomienda en otros comentarios). ¿Qué sucede si tienes más filas que esta cantidad fija? Suponiendo que el siguiente valor de la secuencia es más alto que todos los identificadores de las filas existentes (solo desea llenar los espacios), lo haría como:
UPDATE table SET id = DEFAULT;
ALTER SEQUENCE seq RESTART;
UPDATE table SET id = DEFAULT;