J'ai une table avec plus de millions de lignes. Je dois réinitialiser la séquence et réaffecter la colonne id avec les nouvelles valeurs (1, 2, 3, 4 ... etc ...). Y a-t-il un moyen facile de faire ça?
Si vous ne souhaitez pas conserver l'ordre des identifiants, vous pouvez
ALTER SEQUENCE seq RESTART WITH 1;
UPDATE t SET idcolumn=nextval('seq');
Je doute qu'il y ait un moyen facile de le faire dans l'ordre de votre choix sans recréer la table entière.
Réinitialiser la séquence:
SELECT setval('sequence_name', 0);
Mise à jour des enregistrements actuels:
UPDATE foo SET id = DEFAULT;
Avec PostgreSQL 8.4 ou plus récent, il n’est plus nécessaire de spécifier le WITH 1
. La valeur de départ enregistrée par CREATE SEQUENCE
ou la dernière valeur définie par ALTER SEQUENCE START WITH
sera utilisée (probablement 1).
Réinitialiser la séquence:
ALTER SEQUENCE seq RESTART;
Puis mettez à jour la colonne ID de la table:
UPDATE foo SET id = DEFAULT;
Source: Documents PostgreSQL
Les deux solutions fournies ne fonctionnaient pas pour moi;
> SELECT setval('seq', 0);
ERROR: setval: value 0 is out of bounds for sequence "seq" (1..9223372036854775807)
setval('seq', 1)
commence la numérotation avec 2 et ALTER SEQUENCE seq START 1
commence également avec 2, car seq.is_called est true (Postgres version 9.0.4)
La solution qui a fonctionné pour moi est la suivante:
> ALTER SEQUENCE seq RESTART WITH 1;
> UPDATE foo SET id = DEFAULT;
Juste pour simplifier et clarifier l'utilisation correcte de ALTER SEQUENCE et SELECT setval pour réinitialiser la séquence:
ALTER SEQUENCE sequence_name RESTART WITH 1;
est équivalent à
SELECT setval('sequence_name', 1, FALSE);
Chacune des instructions peut être utilisée pour réinitialiser la séquence et vous pouvez obtenir la valeur suivante avec nextval ('nom_de_séquence') comme indiqué par ici aussi:
nextval('sequence_name')
Le meilleur moyen de réinitialiser une séquence pour recommencer avec le numéro 1 est d'exécuter les tâches suivantes:
ALTER SEQUENCE <tablename>_<id>_seq RESTART WITH 1
Ainsi, par exemple pour la table users, ce serait:
ALTER SEQUENCE users_id_seq RESTART WITH 1
FYI: Si vous avez besoin de spécifier une nouvelle valeur de départ entre une plage d’ID (256 à 10000000 par exemple):
SELECT setval('"Sequence_Name"',
(SELECT coalesce(MAX("ID"),255)
FROM "Table_Name"
WHERE "ID" < 10000000 and "ID" >= 256)+1
);
Pour conserver l'ordre des lignes:
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;
La simple réinitialisation de la séquence et la mise à jour de toutes les lignes peuvent provoquer des erreurs d'identifiant en double. Dans de nombreux cas, vous devez mettre à jour toutes les lignes deux fois. D'abord avec des identifiants plus élevés pour éviter les doublons, puis avec les identifiants que vous voulez réellement.
Évitez d’ajouter un montant fixe à tous les identifiants (comme recommandé dans d’autres commentaires). Que se passe-t-il si vous avez plus de lignes que ce montant fixe? En supposant que la valeur suivante de la séquence est supérieure à tous les identifiants des lignes existantes (vous voulez simplement combler les lacunes), je le ferais comme ceci:
UPDATE table SET id = DEFAULT;
ALTER SEQUENCE seq RESTART;
UPDATE table SET id = DEFAULT;
Dans mon cas, j'ai réalisé ceci avec:
ALTER SEQUENCE table_tabl_id_seq RESTART WITH 6;
Où ma table est nommée table
Même la colonne d'incrémentation automatique n'est pas PK (dans cet exemple, elle s'appelle seq - aka sequence), vous pouvez y parvenir avec un déclencheur:
DROP TABLE SI EXISTS devops_guide CASCADE;
SELECT 'create the "devops_guide" table'
;
CREATE TABLE devops_guide (
guid UUID NOT NULL DEFAULT gen_random_uuid()
, level integer NULL
, seq integer NOT NULL DEFAULT 1
, name varchar (200) NOT NULL DEFAULT 'name ...'
, description text NULL
, CONSTRAINT pk_devops_guide_guid PRIMARY KEY (guid)
) WITH (
OIDS=FALSE
);
-- START trg_devops_guide_set_all_seq
CREATE OR REPLACE FUNCTION fnc_devops_guide_set_all_seq()
RETURNS TRIGGER
AS $$
BEGIN
UPDATE devops_guide SET seq=col_serial FROM
(SELECT guid, row_number() OVER ( ORDER BY seq) AS col_serial FROM devops_guide ORDER BY seq) AS tmp_devops_guide
WHERE devops_guide.guid=tmp_devops_guide.guid;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_devops_guide_set_all_seq
AFTER UPDATE OR DELETE ON devops_guide
FOR EACH ROW
WHEN (pg_trigger_depth() < 1)
EXECUTE PROCEDURE fnc_devops_guide_set_all_seq();
Inspiré par les autres réponses ici, j'ai créé une fonction SQL pour effectuer une migration de séquence. La fonction déplace une séquence de clé primaire vers une nouvelle séquence contiguë commençant par une valeur (> = 1) située à l'intérieur ou à l'extérieur de la plage de séquence existante.
J'explique ici comment j'ai utilisé cette fonction lors de la migration de deux bases de données avec le même schéma mais des valeurs différentes dans une base de données.
Tout d’abord, la fonction (qui affiche les commandes SQL générées de manière à ce que Clarifie ce qui se passe réellement):
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 fonction migrate_pkey_sequence
prend les arguments suivants:
arg_table
: nom de la table (par exemple 'example'
)arg_column
: nom de colonne de la clé primaire (par exemple 'id'
)arg_sequence
: nom de la séquence (par exemple 'example_id_seq'
)arg_next_value
: valeur suivante pour la colonne après la migrationIl effectue les opérations suivantes:
nextval('example_id_seq')
suit max(id)
et que la séquence commence Par 1. Ceci traite également le cas où arg_next_value > max(id)
.arg_next_value
. L'ordre des valeurs de clé est conservé, mais les trous de la plage Ne le sont pas.Pour démontrer, nous utilisons une séquence et une table définies comme suit (par exemple, en utilisant 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)
);
Ensuite, nous insérons quelques valeurs (en commençant par 3):
# ALTER SEQUENCE example_id_seq RESTART WITH 3;
# INSERT INTO example VALUES (DEFAULT), (DEFAULT), (DEFAULT);
-- id: 3, 4, 5
Enfin, nous migrons les valeurs example.id
pour commencer avec 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)
Le résultat:
# SELECT * FROM example;
id
----
1
2
3
(3 rows)