Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

postgresql duplicate key violates unique constraint

Tags:

postgresql

I have a question I know this was posted many times but I didn't find an answer to my problem. The problem is that I have a table and a column "id" I want it to be unique number just as normal. This type of column is serial and the next value after each insert is coming from a sequence so everything seems to be all right but it still sometimes shows this error. I don't know why. In the documentation, it says the sequence is foolproof and always works. If I add a UNIQUE constraint to that column will it help? I worked before many times on Postres but this error is showing for me for the first time. I did everything as normal and I never had this problem before. Can you help me to find the answer that can be used in the future for all tables that will be created? Let's say we have something easy like this:

CREATE TABLE comments (   id serial NOT NULL,   some_column text NOT NULL,   CONSTRAINT id_pkey PRIMARY KEY (id) ) WITH (   OIDS=FALSE ); ALTER TABLE interesting.comments OWNER TO postgres; 

If i add:

ALTER TABLE comments ADD CONSTRAINT id_id_key UNIQUE(id) 

Will if be enough or is there some other thing that should be done?

like image 614
red Avatar asked Dec 15 '10 09:12

red


People also ask

How to avoid duplicate key value violates unique constraint Postgres?

How to fix PostgreSQL error "duplicate key violates unique constraint" SELECT setval('the_primary_key_sequence', (SELECT MAX(the_primary_key) FROM the_table)+1); That will set the sequence to the next available value that's higher than any existing primary key in the sequence.

What does duplicate key value mean?

A duplicate key error means that you have tried to insert a row with the same key value as some other row already indexed by the named index.


2 Answers

This article explains that your sequence might be out of sync and that you have to manually bring it back in sync.

An excerpt from the article in case the URL changes:

If you get this message when trying to insert data into a PostgreSQL database:

ERROR:  duplicate key violates unique constraint 

That likely means that the primary key sequence in the table you're working with has somehow become out of sync, likely because of a mass import process (or something along those lines). Call it a "bug by design", but it seems that you have to manually reset the a primary key index after restoring from a dump file. At any rate, to see if your values are out of sync, run these two commands:

SELECT MAX(the_primary_key) FROM the_table;    SELECT nextval('the_primary_key_sequence'); 

If the first value is higher than the second value, your sequence is out of sync. Back up your PG database (just in case), then run this command:

SELECT setval('the_primary_key_sequence', (SELECT MAX(the_primary_key) FROM the_table)+1); 

That will set the sequence to the next available value that's higher than any existing primary key in the sequence.

like image 192
adamo Avatar answered Sep 22 '22 01:09

adamo


Intro

I also encountered this problem and the solution proposed by @adamo was basically the right solution. However, I had to invest a lot of time in the details, which is why I am now writing a new answer in order to save this time for others.

Case

My case was as follows: There was a table that was filled with data using an app. Now a new entry had to be inserted manually via SQL. After that the sequence was out of sync and no more records could be inserted via the app.

Solution

As mentioned in the answer from @adamo, the sequence must be synchronized manually. For this purpose the name of the sequence is needed. For Postgres, the name of the sequence can be determined with the command PG_GET_SERIAL_SEQUENCE. Most examples use lower case table names. In my case the tables were created by an ORM middleware (like Hibernate or Entity Framework Core etc.) and their names all started with a capital letter.

In an e-mail from 2004 (link) I got the right hint.

(Let's assume for all examples, that Foo is the table's name and Foo_id the related column.)

Command to get the sequence name:

SELECT PG_GET_SERIAL_SEQUENCE('"Foo"', 'Foo_id'); 

So, the table name must be in double quotes, surrounded by single quotes.

1. Validate, that the sequence is out-of-sync

SELECT CURRVAL(PG_GET_SERIAL_SEQUENCE('"Foo"', 'Foo_id')) AS "Current Value", MAX("Foo_id") AS "Max Value" FROM "Foo"; 

When the Current Value is less than Max Value, your sequence is out-of-sync.

2. Correction

SELECT SETVAL((SELECT PG_GET_SERIAL_SEQUENCE('"Foo"', 'Foo_id')), (SELECT (MAX("Foo_id") + 1) FROM "Foo"), FALSE); 
like image 39
SommerEngineering Avatar answered Sep 23 '22 01:09

SommerEngineering