ON CONFLICT makes inserts resilient when a row violates a primary-key or other uniqueness constraint. Choose whether to ignore the incoming row or merge its values into the existing row. section 3.4.1 section 3.4.2
Use the clause according to the desired data workflow:
- Use ON CONFLICT DO NOTHING to make a repeated insert harmless; by default, it targets the primary index. section 3.4.1
- Name a conflict target, such as valid_from or (system_id, read_on), when a specific uniqueness rule should trigger the action. section 3.4.1 section 3.4.2
- Use DO UPDATE to replace or combine existing values; expressions and CASE statements are allowed. section 3.4.2
- Prefer explicit columns and generated IDs rather than suppressing errors caused by fragile positional inserts. section 3.4.1
Average readings that share a device and timestamp
Insert a new reading, then merge a conflicting reading into the existing row: INSERT INTO readings(system_id, read_on, power) VALUES (10, '2023-06-05 13:00:00', 3000) ON CONFLICT(system_id, read_on) DO UPDATE SET power = CASE WHEN power = 0 THEN excluded.power ELSE (power + excluded.power) / 2 END; The conflict target uses the composed key, while excluded.power refers to the incoming value. section 3.4.2
Listing 3.8 Computing new values on conflict
INSERT INTO readings(system_id, read_on, power) VALUES (10, '2023-06-05 13:00:00', 4000); INSERT INTO readings(system_id, read_on, power) VALUES (10, '2023-06-05 13:00:00', 3000) ON CONFLICT(system_id, read_on) DO UPDATE #1 SET power = CASE WHEN power = 0 THEN excluded.power #2 ELSE (power + excluded.power) / 2 END;
Inspect the complete two-step reading merge, including the initial insert and the conflict update. section 3.4.2
