Home > Blockchain >  PostgreSQL : ON CONFLICT DO UPDATE with primary key error
PostgreSQL : ON CONFLICT DO UPDATE with primary key error

Time:05-10

I try to set up a constraint in my query : I got one column that contain a token and I want to change it if necessary. So I set up my query like this :

INSERT INTO mytable (username,uuid,token)
values ('john','someUUID','token')
ON CONFLICT (token)
    DO UPDATE
        SET token = EXCLUDED.token

I thought that works but pgSQL give me the following error :

ERROR:  duplicate key value violates unique constraint "mytable_uuid_unique"
DETAIL:  Key (uuid)=(someUUID) already exists.
SQL state: 23505

It seems that pgSQL want to duplicate the row... How can I just edit my column ?

PS : My table :

CREATE TABLE public.mytable (
    username character varying(40) NOT NULL PRIMARY KEY,
    uuid character varying(64) NOT NULL,
    token character varying(41)
);

ALTER TABLE ONLY mytable
    ADD CONSTRAINT mytable_token_unique UNIQUE (token);


ALTER TABLE ONLY mytable
    ADD CONSTRAINT mytable_username_unique UNIQUE (username);

ALTER TABLE ONLY mytable
    ADD CONSTRAINT mytable_uuid_unique UNIQUE (uuid);

EDIT_ To be more precise, I want to do this query on a empty table:

INSERT INTO mytable (username,uuid,token)
values ('john','someUUID','token')
ON CONFLICT (token)
    DO UPDATE
        SET token = EXCLUDED.token

And later do this query :

INSERT INTO mytable (username,uuid,token)
values ('john','someUUID','token2')
ON CONFLICT (token)
    DO UPDATE
        SET token = EXCLUDED.token

And the only column that is modified is token (from 'token' to 'token2') Hope that is more clear

CodePudding user response:

I tested your code and works fine, pg14.2

u: postgres db: testpart # CREATE TABLE public.mytable (
#     username character varying(40) NOT NULL PRIMARY KEY,
#     uuid character varying(64) NOT NULL,
#     token character varying(41)
# );
CREATE TABLE
Time: 60.377 ms
u: postgres db: testpart # 
u: postgres db: testpart # ALTER TABLE ONLY mytable
#     ADD CONSTRAINT mytable_token_unique UNIQUE (token);
ALTER TABLE
Time: 8.605 ms
u: postgres db: testpart # 
u: postgres db: testpart # 
u: postgres db: testpart # ALTER TABLE ONLY mytable
#     ADD CONSTRAINT mytable_username_unique UNIQUE (username);
ALTER TABLE
Time: 4.810 ms
u: postgres db: testpart # 
u: postgres db: testpart # ALTER TABLE ONLY mytable
#     ADD CONSTRAINT mytable_uuid_unique UNIQUE (uuid);
ALTER TABLE
Time: 5.074 ms
u: postgres db: testpart # 
u: postgres db: testpart # INSERT INTO mytable (username,uuid,token)
# values ('john','someUUID','token')
# ON CONFLICT (token)
#     DO UPDATE
#         SET token = EXCLUDED.token;
INSERT 0 1
Time: 11.091 ms
u: postgres db: testpart # INSERT INTO mytable (username,uuid,token)
values ('john','someUUID','token')
ON CONFLICT (token)
    DO UPDATE
        SET token = EXCLUDED.token;
INSERT 0 1
Time: 6.142 ms
u: postgres db: testpart # INSERT INTO mytable (username,uuid,token)
values ('john','someUUID','token')
ON CONFLICT (token)
    DO UPDATE
        SET token = EXCLUDED.token;
INSERT 0 1
Time: 5.112 ms
u: postgres db: testpart # select * from mytable;
 username |   uuid   | token 
---------- ---------- -------
 john     | someUUID | token
(1 row)

Time: 0.450 ms

CodePudding user response:

I got no error in my dbfiddle until I change 'token' to 'token2' and username 'John' to 'John1' in the 2nd insert statement.

 -- first row insert
    INSERT INTO mytable (username,uuid,token)
    values ('john','someUUID','token')
    ON CONFLICT (token)
        DO UPDATE
            SET token = EXCLUDED.token;
    -- here is the error 
    INSERT INTO mytable (username,uuid,token)
    values ('john1','someUUID','token2')
    ON CONFLICT (token)
        DO UPDATE
            SET token = EXCLUDED.token;
    
    ERROR:  duplicate key value violates unique constraint "mytable_uuid_unique"
    DETAIL:  Key (uuid)=(someUUID) already exists.

In this case, the error is here because you are trying to insert the second row with a unique key already existing in the table by uuid ('someUUID').

Feel free to change my code or variable values to show us the error you are getting.

I would also like to clarify what is the reason to creating these unique indexes (separately for each column)? Maybe it makes sense to change them to a composite index?

CodePudding user response:

You should have ON CONFLICT (username) ,because error caused by constraint on this column you want to handle

INSERT INTO mytable (username,uuid,token)
values ('john','someUUID','token2')
ON CONFLICT (username)
    DO UPDATE
        SET token = EXCLUDED.token

Still, there are 2 unique keys (beside token) in this table. If fields username and uuid are set only during insert, than uuid can be used interchangeable in ON CONFLICT. But if one of this fields (uuid,username) can be changed after inserting then there are some more complicated scenarios you must take care of.

CodePudding user response:

You can reproduce the error like this:

INSERT INTO mytable (username, uuid, token)
   VALUES ('john', '00000000-0000-0000-0000-000000000000', 'token')
   ON CONFLICT (token)
      DO UPDATE SET token = EXCLUDED.token;

INSERT 0 1

INSERT INTO mytable (username, uuid, token)
   VALUES ('john2', '00000000-0000-0000-0000-000000000000', 'token2')
   ON CONFLICT (token)
      DO UPDATE SET token = EXCLUDED.token;

ERROR:  duplicate key value violates unique constraint "mytable_uuid_unique"
DETAIL:  Key (uuid)=(00000000-0000-0000-0000-000000000000) already exists.

The second insert does not have a conflict on token, so the ON CONFLICT clause does not apply. So the INSERT proceeds and gives you a constraint violation because of the duplicate entry for uuid.

That should be just what you want, judging from your constraint definitions.

  • Related