pg_get_serial_sequence
peut être utilisé pour éviter toute supposition incorrecte sur le nom de la séquence. Cela permet de réinitialiser la séquence en une seule fois :
SELECT pg_catalog.setval(pg_get_serial_sequence('table_name', 'id'), (SELECT MAX(id) FROM table_name)+1);
Ou de manière plus concise :
SELECT pg_catalog.setval(pg_get_serial_sequence('table_name', 'id'), MAX(id)) FROM table_name;
Cependant, ce formulaire ne peut pas gérer correctement les tables vides, puisque max(id) est nul, et vous ne pouvez pas non plus définir la valeur 0, car elle serait hors de portée de la séquence. Une solution de contournement consiste à recourir à la fonction ALTER SEQUENCE
syntaxe, c'est-à-dire
ALTER SEQUENCE table_name_id_seq RESTART WITH 1;
ALTER SEQUENCE table_name_id_seq RESTART; -- 8.4 or higher
Mais ALTER SEQUENCE
est d'une utilité limitée car le nom de la séquence et la valeur de redémarrage ne peuvent pas être des expressions.
Il semble que la meilleure solution polyvalente soit d'appeler setval
avec false comme 3ème paramètre, ce qui nous permet de spécifier la "prochaine valeur à utiliser" :
SELECT setval(pg_get_serial_sequence('t1', 'id'), coalesce(max(id),0) + 1, false) FROM t1;
C'est tout ce que je recherche :
- évite de coder en dur le nom réel de la séquence
- gère correctement les tables vides
- gère les tables avec des données existantes, et ne laisse pas un trou dans la séquence
Enfin, notez que pg_get_serial_sequence
ne fonctionne que si la séquence est possédée par la colonne. Ce sera le cas si la colonne d'incrémentation a été définie en tant que serial
Cependant, si la séquence a été ajoutée manuellement, il est nécessaire de s'assurer que ALTER SEQUENCE .. OWNED BY
est également effectuée.
c'est-à-dire que si serial
a été utilisé pour la création de la table, tout devrait fonctionner :
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;
Mais si les séquences ont été ajoutées manuellement :
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;
1 votes
Je suis curieux est-ce que vous laissez tomber la base de données avant de faire une restauration ? Je me souviens vaguement que cela s'est produit, mais je peux me tromper :P
39 votes
Le wiki de PostgreSQL a une page sur Correction des séquences .
26 votes
Juste pour aider à la googlelisation, le message d'erreur envoyé ici est : "La valeur de la clé dupliquée viole la contrainte d'unicité..."
5 votes
Voici comment sqlsequencereset dans Django le fait : SELECT setval(pg_get_serial_sequence("<nom_table>", 'id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "<nom_table>" ;
1 votes
La première instance du <nom de la table> doit être entourée de guillemets simples pour que la fonction pg_get_serioal_sequence fonctionne : SELECT setval(pg_get_serioal_sequence('<nom_table>', 'id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "<nom_table>"
0 votes
Question connexe : stackoverflow.com/questions/62059947/
0 votes
stackoverflow.com/questions/244243/