Just place both keys in the ON CONFLICT
clause:
INSERT INTO answer VALUES (1,1,'q1')
ON CONFLICT (person_id,question_id)
DO UPDATE SET answer = EXCLUDED.answer;
Example:
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)
Demo: db<>fiddle
PostgreSQL 15 +
You can also achieve the same result using 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);
Demo: db<>fiddle