I have a table with over million rows. I need to reset sequence and reassign id column with new values (1, 2, 3, 4... etc...). Is any easy way to do that?
-
8The real question: why on earth would you want to do that? Presumably the ID is the primary key, so there is no benefit whatsoever in changing the primary key. A primary key is a meaningless (in your case artifical) value. "Renumbering" it does not serve any sensible purpose in a relational database. – Jan 13 '11 at 22:08
-
2Initially I had the app running locally, then I copied the data onto production. But `id`s there didn't start from 1. So the ordering turned out as follows: 150, 151..., 300, 1, 2... And it would cause duplicate id errors eventually I suppose, if I hadn't renumbered the ids. Additionally, order by `id` is generally better than order by `created_at`. And here's [what worked for me](http://gbif.blogspot.com/2011/06/ordered-updates-with-postgres.html). – x-yuri Mar 30 '15 at 12:52
-
The point of doing this is so that you can continue to use a regular int instead of bigint for a primary key in a database that continues to increment the sequential key but constantly receives new data. You'll quickly run into the signed integer limit, and if retaining extant id isn't important, this process will bring you back to manageable id numbers. – Ben Wilson Jun 25 '19 at 13:35
-
1Another use for this is testing. You want to reset a table to a known state before starting each test and that requires ids to be reset. – Safa Alai May 14 '20 at 23:22
16 Answers
If you don't want to retain the ordering of ids, then you can
ALTER SEQUENCE seq RESTART WITH 1;
UPDATE t SET idcolumn=nextval('seq');
I doubt there's an easy way to do that in the order of your choice without recreating the whole table.

- 138,757
- 24
- 193
- 173
-
5
-
13This might cause duplicate ids. To prevent this, you can first set all to very high values: UPDATE t SET idcolumn=1000000+ nextval('seq'); then run the above script. – tahagh Nov 28 '13 at 13:15
-
9`SELECT setval('seq', 1, FALSE)` should do the same (here, the third argument, FALSE, does the magic, as it shows that `nextval` must be 1 instead of 2) – Vasilen Donchev Sep 22 '15 at 14:43
-
-
For postgres if you get an error about `Unsafe query: 'Update' statement without 'where' updates all table rows at once` you can add `WHERE idcolumn > 0` – Sabrina Leggett Sep 21 '22 at 18:26
With PostgreSQL 8.4 or newer there is no need to specify the WITH 1
anymore. The start value that was recorded by CREATE SEQUENCE
or last set by ALTER SEQUENCE START WITH
will be used (most probably this will be 1).
Reset the sequence:
ALTER SEQUENCE seq RESTART;
Then update the table's ID column:
UPDATE foo SET id = DEFAULT;
Source: PostgreSQL Docs

- 13,878
- 4
- 40
- 60

- 1,530
- 1
- 12
- 9
-
7This seems like the best answer as it avoids making assumptions about the start value of the sequence. – sheepdog Oct 02 '18 at 03:50
-
2Best answer for my case too. I combine this answer with [this one](https://stackoverflow.com/questions/5342440/reset-auto-increment-counter-in-postgres), which explains the ALTER SEQUENCE command ... so I changed 'seq' by ***mytable_id_seq*** where 'mytable' is my table name and 'id' is the name of my serial column – Javi May 04 '20 at 09:19
-
That's interesting how setval('seq', 1) giving nextval result as 2, but restarting sequence giving nextval as 1. and setval('seq', 0) giving exception – Alexander.Iljushkin Oct 21 '22 at 07:53
Reset the sequence:
SELECT setval('sequence_name', 0);
Updating current records:
UPDATE foo SET id = DEFAULT;

- 117,544
- 24
- 142
- 135
-
7Sequence could have a minimum value greater than 0. (And the default minimum value used by type `serial` and `CREATE SEQUENCE` is 1!) – kbridge4096 Apr 11 '18 at 03:16
The best way to reset a sequence to start back with number 1 is to execute the following:
ALTER SEQUENCE <tablename>_<id>_seq RESTART WITH 1
So, for example for the users table it would be:
ALTER SEQUENCE users_id_seq RESTART WITH 1

- 3,456
- 3
- 23
- 23
Just for simplifying and clarifying the proper usage of ALTER SEQUENCE and SELECT setval for resetting the sequence:
ALTER SEQUENCE sequence_name RESTART WITH 1;
is equivalent to
SELECT setval('sequence_name', 1, FALSE);
Either of the statements may be used to reset the sequence and you can get the next value by nextval('sequence_name') as stated here also:
nextval('sequence_name')

- 3,045
- 26
- 20
-
1Thanks Ali. I've just noticed it's crucial to set that 3rd parameter to false with the setval function – DavidHyogo Mar 07 '18 at 15:11
Both provided solutions did not work for me;
> SELECT setval('seq', 0);
ERROR: setval: value 0 is out of bounds for sequence "seq" (1..9223372036854775807)
setval('seq', 1)
starts the numbering with 2, and ALTER SEQUENCE seq START 1
starts the numbering with 2 as well, because seq.is_called is true (Postgres version 9.0.4)
The solution that worked for me is:
> ALTER SEQUENCE seq RESTART WITH 1;
> UPDATE foo SET id = DEFAULT;

- 5,539
- 1
- 34
- 48
To retain order of the rows:
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;

- 3,880
- 1
- 27
- 21
SELECT SETVAL('seq_my_table_pk_id', (SELECT MAX(my_table_pk_id) + 1 FROM my_table));

- 375
- 3
- 7
FYI: If you need to specify a new startvalue between a range of IDs (256 - 10000000 for example):
SELECT setval('"Sequence_Name"',
(SELECT coalesce(MAX("ID"),255)
FROM "Table_Name"
WHERE "ID" < 10000000 and "ID" >= 256)+1
);

- 235
- 1
- 3
- 9
Just resetting the sequence and updating all rows may cause duplicate id errors. In many cases you have to update all rows twice. First with higher ids to avoid the duplicates, then with the ids you actually want.
Please avoid to add a fixed amount to all ids (as recommended in other comments). What happens if you have more rows than this fixed amount? Assuming the next value of the sequence is higher than all the ids of the existing rows (you just want to fill the gaps), i would do it like:
UPDATE table SET id = DEFAULT;
ALTER SEQUENCE seq RESTART;
UPDATE table SET id = DEFAULT;

- 61
- 2
- 4
In my case, I achieved this with:
ALTER SEQUENCE table_tabl_id_seq RESTART WITH 6;
Where my table is named table

- 8,218
- 8
- 36
- 58

- 4,325
- 39
- 27
-
2Thanks for including a concrete example with your table name. The other answers were a bit too ambiguous. – Brylie Christopher Oxley Feb 26 '18 at 09:35
In my case sequences in all tables had been corrupted after importing the wrong sql file. SELECT nextval('table_name_id_seq');
was returning less than max value of the id
column.
So, I created sql script to recover all sequences for each table:
DO
$$
DECLARE
rec record;
table_seq text;
BEGIN
FOR rec IN
SELECT *
FROM pg_tables
WHERE tablename NOT LIKE 'pg\_%'
ORDER BY tablename
LOOP
table_seq := rec.tablename || '_id_seq';
RAISE NOTICE '%', table_seq;
EXECUTE format(E'SELECT setval(\'%I\', COALESCE((SELECT MAX(id)+1 FROM %I), 1), false);',
table_seq, rec.tablename);
END LOOP;
END
$$;
Note: If you don't have the id
column on any of your tables, you would either update the logic or handle them separately based on the logic above.
For example, to update the value of sequence "SEQ_A" using the maximum value of the "FIELD_ID" field of table "TAB_B," you can use the following command:
SELECT setval('SEQ_A', (SELECT max(FIELD_ID) FROM TAB_B));
This command selects the maximum value of the "FIELD_ID" field of table "TAB_B" and sets it as the next value of sequence "SEQ_A."

- 41
- 2
-
Thank you for answering, @sennin. While your answer is absolutely correct, it mainly repeats things that were answered years ago already. – Christian Severin Jan 17 '23 at 13:58
If you are using pgAdmin3, expand 'Sequences,' right click on a sequence, go to 'Properties,' and in the 'Definition' tab change 'Current value' to whatever value you want. There is no need for a query.

- 2,327
- 1
- 19
- 41

- 1,042
- 10
- 13
-
3Your answer adds no value if you don't at least tell us what tool you are using. – 11101101b Feb 19 '14 at 15:47
-
3
Inspired by the other answers here, I created an SQL function to do a sequence migration. The function moves a primary key sequence to a new contiguous sequence starting with any value (>= 1) either inside or outside the existing sequence range.
I explain here how I used this function in a migration of two databases with the same schema but different values into one database.
First, the function (which prints the generated SQL commands so that it is clear what is actually happening):
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;
The function migrate_pkey_sequence
takes the following arguments:
arg_table
: table name (e.g.'example'
)arg_column
: primary key column name (e.g.'id'
)arg_sequence
: sequence name (e.g.'example_id_seq'
)arg_next_value
: next value for the column after migration
It performs the following operations:
- Move the primary key values to a free range. I assume that
nextval('example_id_seq')
followsmax(id)
and that the sequence starts with 1. This also handles the case wherearg_next_value > max(id)
. - Move the primary key values to the contiguous range starting with
arg_next_value
. The order of key values are preserved but holes in the range are not preserved. - Print the next value that would follow in the sequence. This is useful if you want to migrate the columns of another table and merge with this one.
To demonstrate, we use a sequence and table defined as follows (e.g. using 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)
);
Then, we insert some values (starting, for example, at 3):
# ALTER SEQUENCE example_id_seq RESTART WITH 3;
# INSERT INTO example VALUES (DEFAULT), (DEFAULT), (DEFAULT);
-- id: 3, 4, 5
Finally, we migrate the example.id
values to start with 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)
The result:
# SELECT * FROM example;
id
----
1
2
3
(3 rows)

- 1
- 1

- 1,182
- 1
- 9
- 25
Even the auto-increment column is not PK ( in this example it is called seq - aka sequence ) you could achieve that with a trigger :
DROP TABLE IF 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();

- 5,114
- 1
- 56
- 53