pg_get_serial_sequence
can be used to avoid any incorrect assumptions about the sequence name. This resets the sequence in one shot:
SELECT pg_catalog.setval(pg_get_serial_sequence('table_name', 'id'), (SELECT MAX(id) FROM table_name)+1);
Or more concisely:
SELECT pg_catalog.setval(pg_get_serial_sequence('table_name', 'id'), MAX(id)) FROM table_name;
However this form can't handle empty tables correctly, since max(id) is null, and neither can you setval 0 because it would be out of range of the sequence. One workaround for this is to resort to the ALTER SEQUENCE
syntax i.e.
ALTER SEQUENCE table_name_id_seq RESTART WITH 1;
ALTER SEQUENCE table_name_id_seq RESTART; -- 8.4 or higher
But ALTER SEQUENCE
is of limited use because the sequence name and restart value cannot be expressions.
It seems the best all-purpose solution is to call setval
with false as the 3rd parameter, allowing us to specify the "next value to use":
SELECT setval(pg_get_serial_sequence('t1', 'id'), coalesce(max(id),0) + 1, false) FROM t1;
This ticks all my boxes:
- avoids hard-coding the actual sequence name
- handles empty tables correctly
- handles tables with existing data, and does not leave a
hole in the sequence
Finally, note that pg_get_serial_sequence
only works if the sequence is owned by the column. This will be the case if the incrementing column was defined as a serial
type, however if the sequence was added manually it is necessary to ensure ALTER SEQUENCE .. OWNED BY
is also performed.
i.e. if serial
type was used for table creation, this should all work:
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;
But if sequences were added manually:
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;