web-dev-qa-db-fra.com

Postgres on conflict met à jour les clés primaires composites

J'ai un tableau où un utilisateur répond à une question. Les règles sont que l'utilisateur peut répondre à de nombreuses questions ou que de nombreux utilisateurs peuvent répondre à une question MAIS un utilisateur ne peut répondre à une question particulière qu'une seule fois. Si l'utilisateur répond à nouveau à la question, celle-ci doit simplement remplacer l'ancienne. Généralement, le conflit sur met à jour les travaux lorsque nous avons affaire à des colonnes uniques. Dans ce scénario, les colonnes person_id et question_id ne peut pas être unique. Cependant, la combinaison des deux est toujours unique. Comment implémenter l'instruction d'insertion qui se met à jour en cas de conflit?

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) 
);
10
pewpewlasers

Placez simplement les deux clés dans le ON CONFLICT clause:

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

Exemple:

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-UPDATED') 
ON CONFLICT (person_id,question_id) 
DO UPDATE SET answer = EXCLUDED.answer;             

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

Vous pouvez également définir le primaire à l'extérieur de la table et vous n'avez pas besoin de réécrire toutes les colonnes qui y sont incluses.

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);

Puis:

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

Lorsque la contrainte change à l'avenir, vous n'avez pas besoin d'ajuster manuellement les instructions d'insertion pour refléter cela.