334

I'm trying to set a sequence to a specific value.

SELECT setval('payments_id_seq'), 21, true;

This gives an error:

ERROR: function setval(unknown) does not exist

Using ALTER SEQUENCE doesn't seem to work either?

ALTER SEQUENCE payments_id_seq LASTVALUE 22;

How can this be done?

Ref: https://www.postgresql.org/docs/current/functions-sequence.html

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
stef
  • 26,771
  • 31
  • 105
  • 143

8 Answers8

524

The parentheses are misplaced:

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

Otherwise you're calling setval with a single argument, while it requires two or three.

This is the same as SELECT setval('payments_id_seq', 21)

ChrisGPT was on strike
  • 127,765
  • 105
  • 273
  • 257
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • 12
    What does the last argument "true" means? – inafalcao Sep 27 '17 at 12:16
  • 60
    `true` means that the next value will be the number provided + 1, in this case 22. `false` means that the next value would be the number provided, or 21. By default, setval will behave as if `true` was chosen. More details: https://www.postgresql.org/docs/9.6/static/functions-sequence.html – Tom Mertz Nov 07 '17 at 20:11
  • 10
    an advantage of the `select setval` syntax over `alter sequence` is that you can use nested queries in it, for example to `select max(id) from payments`. – mariotomo Jul 11 '19 at 20:13
  • @mariotomo that's an excellent point, and one of the easiest ways to ensure you don't accidently introduce a latent bug by setting the sequence number lower than the current max – John Neuhaus Sep 29 '20 at 16:40
  • 1
    Another advantage of using such functions is running queries like `select setval('new_id_seq', nextval('old_id_seq'), false);` which helps to migrate – Shiplu Mokaddim Jan 25 '23 at 00:07
280

This syntax isn't valid in any version of PostgreSQL:

ALTER SEQUENCE payments_id_seq LASTVALUE 22

This would work:

ALTER SEQUENCE payments_id_seq RESTART WITH 22;

And is equivalent to:

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

More in the current manual for ALTER SEQUENCE and sequence functions.

Note that setval() expects either (regclass, bigint) or (regclass, bigint, boolean). In the above example I am providing untyped literals. That works too. But if you feed typed variables to the function you may need explicit type casts to satisfy function type resolution. Like:

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

For repeated operations you might be interested in:

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

START [WITH] stores a default RESTART number, which is used for subsequent RESTART calls without value. You need Postgres 8.4 or later for the last part.

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
  • 8
    `ALTER SEQUENCE [sequence] RESTART WITH (SELECT MAX(col) from table);` does not work, whereas `SELECT setval('sequence', (SELECT (MAX(col) from table), TRUE);` does work. I get a syntax error. (Postgres 9.4) – NuclearPeon Jul 21 '18 at 01:35
  • 2
    No subquery allowed in a DDL command ("utility command"). See: https://stackoverflow.com/a/36025963/939860 – Erwin Brandstetter Jul 21 '18 at 02:49
  • @NuclearPeon that doesn't work either. Always gives syntax error function setval(unknown, numeric, boolean) does not exist. – Mital Pritmani Oct 04 '18 at 11:00
  • 1
    @MitalPritmani: You may need type casts. Consider added instructions above. – Erwin Brandstetter Oct 04 '18 at 12:35
  • 2
    @NuclearPeon I think you mean `SELECT setval('sequence', (SELECT MAX(col) from table), TRUE);` otherwise your parens don't line up. – dland Mar 19 '19 at 11:13
  • 5
    @dland: Aside: shorter & faster equivalent: `SELECT setval('seq', max(col)) FROM tbl;` See: https://stackoverflow.com/a/23390399/939860 – Erwin Brandstetter Mar 19 '19 at 11:22
  • I like the last one as it allows me to calculate the value :) – Alejandro Nov 02 '19 at 16:02
  • FWIW, 'ALTER SEQUENCE RESTART WITH' and setval are not 100% equivalent - in my testing, ALTER is blocking, and setval is not, which makes setval suitable for concurrent updates from different transactions - a feature I needed. – Alex Shelemin Jan 19 '22 at 18:27
68

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

setval contains 3 parameters:

  • 1st parameter is sequence_name
  • 2nd parameter is Next nextval
  • 3rd parameter is optional.

The use of true or false in 3rd parameter of setval is as follows:

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

The better way to avoid hard-coding of sequence name, next sequence value and to handle empty column table correctly, you can use the below way:

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

where table_name is the name of the table, id is the primary key of the table

VaibsVB
  • 835
  • 7
  • 9
  • 3
    Thank you! Last expression is exactly what I was looking for. It allows me to reserve the sequence values in order to insert by batch afterwards. – Tim Feb 27 '19 at 09:21
  • 1
    This is the most correct answer, the last SQL snippet is the most generic and effective. – Mick Byrne Aug 09 '22 at 23:24
  • First comment 'Next nextval will return 22'. Just if the increment value of the sequence is 1. It will be 21 + increment value. Third comment 'Next nextval will return 21'. That's always true. Sometimes for generating less network traffic the app gets e.g. 10 ids to use without the need to ask 10 times. And next time the nextval return value will be increased by 10 instead of 1. See increment here https://www.postgresql.org/docs/current/sql-createsequence.html – Arpad Horvath -- Слава Україні Aug 21 '23 at 11:16
10

select setval('sequence_name', sequence_value)

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
Andrzej Bobak
  • 2,106
  • 3
  • 28
  • 36
6

I don't try changing sequence via setval. But using ALTER I was issued how to write sequence name properly. And this only work for me:

  1. Check required sequence name using SELECT * FROM information_schema.sequences;

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

    In my case it was ALTER SEQUENCE public."Services_Id_seq" restart 8;

Also there is a page on wiki.postgresql.org where describes a way to generate sql script to fix sequences in all database tables at once. Below the text from link:

Save this to a file, say '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;

Run the file and save its output in a way that doesn't include the usual headers, then run that output. Example:

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

And the output will be a set of sql commands which look exactly like this:

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
  • 1,094
  • 13
  • 16
2

this worked for me:

SELECT pg_catalog.setval('public.hibernate_sequence', 3, true);
1

This alter it works for me :

ALTER SEQUENCE payments_id_seq
    RESTART 17;

enter image description here

Amine ABBAOUI
  • 175
  • 1
  • 12
0

For most of the people setval command should work, mine was not working so I used pg_catalog.setval.

This one worked for me:

select pg_catalog.setval('<sequence_variable_name>', <sequence_number_you_want>, true);

The setval function alone didn't work for me.

SELECT pg_catalog.setval('payments_id_seq', 21, true); -- next will be 22

See the docs for more info

Ashmin
  • 15
  • 2
  • 10