postgresql 发生冲突的Postgres会更新组合主键

0s7z1bwu  于 2023-01-30  发布在  PostgreSQL
关注(0)|答案(2)|浏览(277)

我有一个用户回答问题的表。规则是用户可以回答许多问题,或者许多用户可以回答一个问题,但用户只能回答一个特定的问题。如果用户再次回答该问题,它应该简单地替换旧的。2一般来说,当我们处理唯一的列时,on conflict do update可以工作。在这个场景中,列person_idquestion_id不能是唯一的,但是这两个列的组合总是唯一的,我如何实现在冲突时更新的insert语句呢?

CREATE TABLE "answer" (
  "person_id" integer NOT NULL REFERENCES person(id), 
  "question_id" integer NOT NULL REFERENCES question(id) ON DELETE CASCADE, /* INDEXED */
  "answer" character varying (1200) NULL,
  PRIMARY KEY (person_id, question_id) 
);
bis0qfac

bis0qfac1#

只需将两个键都放在ON CONFLICT子句中:

INSERT INTO answer VALUES (1,1,'q1') 
ON CONFLICT (person_id,question_id) 
DO UPDATE SET answer = EXCLUDED.answer;

示例:

INSERT INTO answer VALUES (1,1,'q1') 
ON CONFLICT (person_id,question_id) 
DO UPDATE SET answer = EXCLUDED.answer;             

SELECT * FROM answer;
 person_id | question_id | answer 
-----------+-------------+--------
         1 |           1 | q1
(1 Zeile)

INSERT INTO answer VALUES (1,1,'q1') 
ON CONFLICT (person_id,question_id) 
DO UPDATE SET answer = EXCLUDED.answer || '-UPDATED';             

SELECT * FROM answer;
 person_id | question_id |   answer   
-----------+-------------+------------
         1 |           1 | q1-UPDATED
(1 Zeile)

演示:db<>fiddle

PostgreSQL 15+版本

使用MERGE也可以获得相同的结果:

MERGE INTO answer i
  -- records to be inserted
  USING (
    VALUES (1,1,'q1'), -- already exists in table answers!
           (2,2,'q2')  -- new record
  ) AS j (person_id, question_id, answer)
  -- checking if the PK of given records (j) already exists
  -- in table "answer" (i).
  ON j.question_id = i.question_id AND j.person_id = i.person_id
WHEN MATCHED THEN
  -- in case of a match (conflict), I want to add the suffix '-UPDATED' 
  -- to the column "answer"
  UPDATE SET answer = j.answer || '-UPDATED'
WHEN NOT MATCHED THEN 
  -- if there is no match (conflict) just INSERT the record.
  INSERT (person_id, question_id, answer)
  VALUES (j.person_id, j.question_id, j.answer);

演示:db<>fiddle

c0vxltue

c0vxltue2#

您还可以在表的外部定义主列,这样就不需要重写其中包含的所有列。

CREATE TABLE "answer" (
  "person_id" integer NOT NULL REFERENCES person(id), 
  "question_id" integer NOT NULL REFERENCES question(id) ON DELETE CASCADE, /* INDEXED */
  "answer" character varying (1200) NULL);

ALTER TABLE "answer" ADD CONSTRAINT answer_pk PRIMARY KEY (person_id, question_id);

然后:

INSERT INTO answer VALUES (1,1,'q1') ON CONFLICT ON CONSTRAINT answer_pk DO UPDATE SET answer = EXCLUDED.answer;

当约束将来发生变化时,您不需要手动调整insert语句来反映这一点。

相关问题