Postgres modifie manuellement la séquence

203

J'essaie de définir une séquence sur une valeur spécifique.

SELECT setval('payments_id_seq'), 21, true

Cela donne une erreur:

ERROR: function setval(unknown) does not exist

L'utilisation ALTER SEQUENCEne semble pas fonctionner non plus?

ALTER SEQUENCE payments_id_seq LASTVALUE 22

Comment cela peut-il être fait?

Réf: https://www.postgresql.org/docs/current/static/functions-sequence.html

stef
la source
4
Il semblerait que cela setval()a au moins deux arguments.

Réponses:

290

Les parenthèses sont mal placées:

SELECT setval('payments_id_seq', 21, true);  # next value will be 22

Sinon, vous appelez setvalavec un seul argument, alors qu'il en faut deux ou trois.

NPE
la source
3
Que signifie le dernier argument «vrai»?
inafalcao
17
truesignifie que la valeur suivante sera le nombre fourni + 1, dans ce cas 22. falsesignifie que la valeur suivante sera le nombre fourni, ou 21. Par défaut, setval se comportera comme s'il trueavait été choisi. Plus de détails: postgresql.org/docs/9.6/static/functions-sequence.html
Tom Mertz
3
un avantage de la select setvalsyntaxe alter sequenceest que vous pouvez y utiliser des requêtes imbriquées, par exemple pour select max(id) from payments.
mariotomo le
@mariotomo c'est un excellent point, et l'un des moyens les plus simples de vous assurer de ne pas introduire accidentellement un bogue latent en définissant le numéro de séquence inférieur au maximum actuel
John Neuhaus le
199

Cette syntaxe n'est valide dans aucune version de PostgreSQL:

ALTER SEQUENCE payments_id_seq LASTVALUE 22

Cela fonctionnerait:

ALTER SEQUENCE payments_id_seq RESTART WITH 22;

et équivaut à:

SELECT setval('payments_id_seq', 22, FALSE);

Plus dans le courant manuel ALTER SEQUENCEet des fonctions de séquence .

Notez que cela setval()attend soit (regclass, bigint)ou (regclass, bigint, boolean). Dans l'exemple ci-dessus, je fournis des littéraux non typés . Cela fonctionne aussi. Mais si vous fournissez des variables typées à la fonction, vous pouvez avoir besoin de castes de types explicites pour satisfaire la résolution de type de fonction. Comme:

SELECT setval(my_text_variable::regclass, my_other_variable::bigint, FALSE);

Pour les opérations répétées, vous pourriez être intéressé par:

ALTER SEQUENCE payments_id_seq START WITH 22; -- set default
ALTER SEQUENCE payments_id_seq RESTART;       -- without value

START [WITH]stocke un RESTARTnuméro par défaut , qui est utilisé pour les RESTARTappels suivants sans valeur. Vous avez besoin de Postgres 8.4 ou version ultérieure pour la dernière partie.

Erwin Brandstetter
la source
5
ALTER SEQUENCE [sequence] RESTART WITH (SELECT MAX(col) from table);ne fonctionne pas, alors que SELECT setval('sequence', (SELECT (MAX(col) from table), TRUE);ça marche. J'obtiens une erreur de syntaxe. (Postgres 9.4)
NuclearPeon
1
Aucune sous-requête autorisée dans une commande DDL ("commande utilitaire"). Voir: stackoverflow.com/a/36025963/939860
Erwin Brandstetter
1
@MitalPritmani: Vous aurez peut-être besoin de castes de caractères. Considérez les instructions supplémentaires ci-dessus.
Erwin Brandstetter
1
@NuclearPeon Je pense que tu veux dire, SELECT setval('sequence', (SELECT MAX(col) from table), TRUE);sinon tes parents ne s'alignent pas.
dland
1
@dland: Aside: équivalent plus court et plus rapide: SELECT setval('seq', max(col)) FROM tbl;Voir: stackoverflow.com/a/23390399/939860
Erwin Brandstetter
37

Utilisation select setval('payments_id_seq', 21, true);

setval contient 3 paramètres:

  • Le 1er paramètre est sequence_name
  • Le deuxième paramètre est le suivant nextval
  • Le troisième paramètre est facultatif.

L'utilisation de true ou false dans le 3ème paramètre de setval est la suivante:

SELECT setval('payments_id_seq', 21);           // Next nextval will return 22
SELECT setval('payments_id_seq', 21, true);     // Same as above 
SELECT setval('payments_id_seq', 21, false);    // Next nextval will return 21

La meilleure façon d'éviter le codage en dur du nom de séquence, de la valeur de séquence suivante et de gérer correctement la table de colonnes vides, vous pouvez utiliser la méthode ci-dessous:

SELECT setval(pg_get_serial_sequence('table_name', 'id'), coalesce(max(id), 0)+1 , false) FROM table_name;

table_nameest le nom de la table, idest le primary keyde la table

VaibsVB
la source
Merci! La dernière expression est exactement ce que je cherchais. Cela me permet de réserver les valeurs de séquence afin de les insérer par lot par la suite.
Timur
8
setval('sequence_name', sequence_value)
Andrzej Bobak
la source
1

Je n'essaye pas de changer de séquence via setval. Mais en utilisant, on ALTERm'a donné comment écrire correctement le nom de la séquence. Et cela ne fonctionne que pour moi:

  1. Vérifiez le nom de séquence requis à l'aide de SELECT * FROM information_schema.sequences;

  2. ALTER SEQUENCE public."table_name_Id_seq" restart {number};

    Dans mon cas, c'était ALTER SEQUENCE public."Services_Id_seq" restart 8;

Il existe également une page sur wiki.postgresql.org où décrit un moyen de générer un script sql pour corriger les séquences dans toutes les tables de la base de données à la fois. Ci-dessous le texte du lien:

Enregistrez ceci dans un fichier, dites «reset.sql»

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;

Exécutez le fichier et enregistrez sa sortie d'une manière qui n'inclut pas les en-têtes habituels, puis exécutez cette sortie. Exemple:

psql -Atq -f reset.sql -o temp
psql -f temp
rm temp

Et la sortie sera un ensemble de commandes sql qui ressemblent exactement à ceci:

SELECT SETVAL('public."SocialMentionEvents_Id_seq"', COALESCE(MAX("Id"), 1) ) FROM public."SocialMentionEvents";
SELECT SETVAL('public."Users_Id_seq"', COALESCE(MAX("Id"), 1) ) FROM public."Users";
alanextar
la source