Insert, on duplicate update in PostgreSQL?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
PostgreSQL, one of the most advanced open-source relational database systems, offers robust support for complex SQL operations. One common requirement in database management is handling scenarios where you attempt to insert a row that might already exist based on certain unique constraints. If such a row exists, you might want to update it instead of creating a new one. This is often referred to as "upsert" (update or insert). PostgreSQL addresses this need with the ON CONFLICT clause, introduced in version 9.5.
Understanding the ON CONFLICT Clause
The ON CONFLICT clause is used in an INSERT statement to specify an alternative action if the insertion would lead to a duplicate in unique constraint or primary key violation. This feature not only simplifies SQL scripts but also improves their performance by reducing the need for additional queries to check for existing data before insertion.
Syntax of ON CONFLICT
The basic syntax for using ON CONFLICT is as follows:
DO NOTHING: This option tells PostgreSQL to take no action if a conflict occurs. It's useful when you simply want to ignore the duplicate entry.DO UPDATE: This option tells PostgreSQL to update the existing record. You can specify which columns to update and even use expressions to set new values.
Example with ON CONFLICT
Consider a table named products with columns product_id, product_name, and quantity.
Now, let’s see how to use ON CONFLICT during insertion:
In this example, if a product named "Widget" already exists, instead of throwing an error, PostgreSQL will update its quantity by adding the quantity of the new entry to the existing one.
Detailed Use Cases and Considerations
Choosing the Conflict Target
The ON CONFLICT clause requires a conflict target. This target is either a column name or a set of columns which together are subject to a unique constraint. The constraint_column in the syntax refers to this target.
The EXCLUDED Table
In DO UPDATE, the EXCLUDED table is a special table used in PostgreSQL. It holds the proposed row for insertion as it originally appeared before any processing by INSERT. You can reference it to get the values originally proposed for insertion.
Conditional Upsert
You can condition the update using a WHERE clause within the DO UPDATE. This provides control over whether to perform an update based on specific conditions of the existing rows:
In this example, the update will only occur if the resulting quantity is less than 100.
Performance Implications
Using ON CONFLICT properly can result in considerable performance improvements, especially in scenarios where conflict occurrences are common. It reduces the need for prior SELECT queries to check for potential duplicates, leading to fewer round trips to the database.
Summary Table
| Feature | Description |
| Conflict Handling | Allows specification of an alternative action if a conflict occurs |
DO NOTHING | Ignores the write operation for the conflict row |
DO UPDATE | Updates the conflicting row with new values |
| Conflict Target | Must specify which column/set of columns should be checked for conflict |
| Performance | Reduces unnecessary queries and possible round trips to the database |
Conclusion
The ON CONFLICT clause in PostgreSQL offers a powerful way to handle duplicates during insertion, enabling more efficient and cleaner data management procedures. Its ability to conditionally decide between insertion and update in a single operation simplifies code and improves database throughput.

