简体   繁体   English

PostgreSQL:ON CONFLICT DO UPDATE 主键错误

[英]PostgreSQL : ON CONFLICT DO UPDATE with primary key error

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:我认为可行,但 pgSQL 给我以下错误:

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?似乎 pgSQL 想要复制该行...我怎样才能编辑我的列?

PS: My table: PS:我的表:

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唯一修改的列是令牌(从“令牌”到“令牌2”)希望更清楚

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.第二个插入在token上没有冲突,因此ON CONFLICT子句不适用。 So the INSERT proceeds and gives you a constraint violation because of the duplicate entry for uuid .因此INSERT继续进行并由于uuid的重复条目而给您违反约束。

That should be just what you want, judging from your constraint definitions.从您的约束定义来看,这应该正是您想要的。

I tested your code and works fine, pg14.2我测试了你的代码并且工作正常,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

I got no error in my dbfiddle until I change 'token' to 'token2' and username 'John' to 'John1' in the 2nd insert statement.在我将第二个插入语句中的“token”更改为“token2”并将用户名“John”更改为“John1”之前,我的dbfiddle没有出现任何错误。

 -- 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').在这种情况下,错误就在这里,因为您试图插入第二行,其中的唯一键已按 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?也许将它们更改为复合索引有意义?

You should use ON CONFLICT (username) or ON CONFLICT (uuid) ,because in scenario when during inserting new record constraints on this fields are violated, you want to update token instead of inserting a new record.您应该使用ON CONFLICT (username)ON CONFLICT (uuid) ,因为在插入新记录期间违反此字段约束的情况下,您希望更新令牌而不是插入新记录。

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

If fields username and uuid are set only during insert, than you can use uuid interchangeably with username .如果字段usernameuuid仅在插入期间设置,那么您可以将uuidusername互换使用。 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.但是,如果其中一个字段 ( uuid,username ) 可以在插入后更改,那么您必须注意一些更复杂的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM