Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

postgres autoincrement not updated on explicit id inserts

I have the following table in postgres:

CREATE TABLE "test" (     "id" serial NOT NULL PRIMARY KEY,     "value" text ) 

I am doing following insertions:

insert into test (id, value) values (1, 'alpha') insert into test (id, value) values (2, 'beta')  insert into test (value) values ('gamma') 

In the first 2 inserts I am explicitly mentioning the id. However the table's auto increment pointer is not updated in this case. Hence in the 3rd insert I get the error:

ERROR:  duplicate key value violates unique constraint "test_pkey" DETAIL:  Key (id)=(1) already exists. 

I never faced this problem in Mysql in both MyISAM and INNODB engines. Explicit or not, mysql always update autoincrement pointer based on the max row id.

What is the workaround for this problem in postgres? I need it because I want a tighter control for some ids in my table.

UPDATE: I need it because for some values I need to have a fixed id. For other new entries I dont mind creating new ones.

I think it may be possible by manually incrementing the nextval pointer to max(id) + 1 whenever I am explicitly inserting the ids. But I am not sure how to do that.

like image 733
jerrymouse Avatar asked Feb 02 '12 07:02

jerrymouse


People also ask

What is the function used to get the value of recently inserted ID in an autoincrement column?

To obtain the value immediately after an INSERT , use a SELECT query with the LAST_INSERT_ID() function. For example, using Connector/ODBC you would execute two separate statements, the INSERT statement and the SELECT query to obtain the auto-increment value.

Does PostgreSQL create ID auto increment?

PostgreSQL has the data types smallserial, serial and bigserial; these are not true types, but merely a notational convenience for creating unique identifier columns. These are similar to AUTO_INCREMENT property supported by some other databases.

Does update insert in Postgres?

The idea is that when you insert a new row into the table, PostgreSQL will update the row if it already exists, otherwise, it will insert the new row. That is why we call the action is upsert (the combination of update or insert).


2 Answers

That's how it's supposed to work - next_val('test_id_seq') is only called when the system needs a value for this column and you have not provided one. If you provide value no such call is performed and consequently the sequence is not "updated".

You could work around this by manually setting the value of the sequence after your last insert with explicitly provided values:

SELECT setval('test_id_seq', (SELECT MAX(id) from "test")); 

The name of the sequence is autogenerated and is always tablename_columnname_seq.

like image 149
Milen A. Radev Avatar answered Sep 19 '22 13:09

Milen A. Radev


In the recent version of Django, this topic is discussed in the documentation:

Django uses PostgreSQL’s SERIAL data type to store auto-incrementing primary keys. A SERIAL column is populated with values from a sequence that keeps track of the next available value. Manually assigning a value to an auto-incrementing field doesn’t update the field’s sequence, which might later cause a conflict.

Ref: https://docs.djangoproject.com/en/dev/ref/databases/#manually-specified-autoincrement-pk

There is also management command manage.py sqlsequencereset app_label ... that is able to generate SQL statements for resetting sequences for the given app name(s)

Ref: https://docs.djangoproject.com/en/dev/ref/django-admin/#django-admin-sqlsequencereset

For example these SQL statements were generated by manage.py sqlsequencereset my_app_in_my_project:

BEGIN; SELECT setval(pg_get_serial_sequence('"my_project_aaa"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "my_project_aaa"; SELECT setval(pg_get_serial_sequence('"my_project_bbb"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "my_project_bbb"; SELECT setval(pg_get_serial_sequence('"my_project_ccc"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "my_project_ccc"; COMMIT; 
like image 27
illagrenan Avatar answered Sep 20 '22 13:09

illagrenan