--- title: UPSERT summary: The UPSERT statement inserts rows when values do not violate uniqueness constraints, and it updates rows when values do violate uniqueness constraints. toc: true --- The `UPSERT` [statement](sql-statements.html) is semantically equivalent to [`INSERT ON CONFLICT`](insert.html#on-conflict-clause), but the two may have slightly different [performance characteristics](#considerations). It inserts rows in cases where specified values do not violate uniqueness constraints, and it updates rows in cases where values do violate uniqueness constraints. ## Considerations - `UPSERT` considers uniqueness only for [Primary Key](primary-key.html) columns. `INSERT ON CONFLICT` is more flexible and can be used to consider uniqueness for other columns. For more details, see [How `UPSERT` transforms into `INSERT ON CONFLICT`](#how-upsert-transforms-into-insert-on-conflict) below. - When inserting/updating all columns of a table, and the table has no secondary indexes, `UPSERT` will be faster than the equivalent `INSERT ON CONFLICT` statement, as it will write without first reading. This may be particularly useful if you are using a simple SQL table of two columns to [simulate direct KV access](sql-faqs.html#can-i-use-cockroachdb-as-a-key-value-store). - A single [multi-row `UPSERT`](#upsert-multiple-rows) statement is faster than multiple single-row `UPSERT` statements. Whenever possible, use multi-row `UPSERT` instead of multiple single-row `UPSERT` statements. - If the input data contains duplicates, see [Import data containing duplicate rows using `DISTINCT ON`](#import-data-containing-duplicate-rows-using-distinct-on) below. ## Required privileges The user must have the `INSERT`, `SELECT` and `UPDATE` [privileges](authorization.html#assign-privileges) on the table. ## Synopsis
{% include {{ page.version.version }}/sql/diagrams/upsert.html %}
## Parameters Parameter | Description ----------|------------ `common_table_expr` | See [Common Table Expressions](common-table-expressions.html). `table_name` | The name of the table. `AS table_alias_name` | An alias for the table name. When an alias is provided, it completely hides the actual table name. `column_name` | The name of a column to populate during the insert. `select_stmt` | A [selection query](selection-queries.html). Each value must match the [data type](data-types.html) of its column. Also, if column names are listed after `INTO`, values must be in corresponding order; otherwise, they must follow the declared order of the columns in the table. `DEFAULT VALUES` | To fill all columns with their [default values](default-value.html), use `DEFAULT VALUES` in place of `select_stmt`. To fill a specific column with its default value, leave the value out of the `select_stmt` or use `DEFAULT` at the appropriate position. `RETURNING target_list` | Return values based on rows inserted, where `target_list` can be specific column names from the table, `*` for all columns, or computations using [scalar expressions](scalar-expressions.html).

Within a [transaction](transactions.html), use `RETURNING NOTHING` to return nothing in the response, not even the number of rows affected. ## How `UPSERT` transforms into `INSERT ON CONFLICT` `UPSERT` considers uniqueness only for [primary key](primary-key.html) columns. For example, assuming that columns `a` and `b` are the primary key, the following `UPSERT` and `INSERT ON CONFLICT` statements are equivalent: {% include copy-clipboard.html %} ~~~ sql > UPSERT INTO t (a, b, c) VALUES (1, 2, 3); ~~~ {% include copy-clipboard.html %} ~~~ sql > INSERT INTO t (a, b, c) VALUES (1, 2, 3) ON CONFLICT (a, b) DO UPDATE SET c = excluded.c; ~~~ `INSERT ON CONFLICT` is more flexible and can be used to consider uniqueness for columns not in the primary key. For more details, see the [Upsert that Fails (Conflict on Non-Primary Key)](#upsert-that-fails-conflict-on-non-primary-key) example below. ## Examples ### Upsert a row (no conflict) In this example, the `id` column is the primary key. Because the inserted `id` value does not conflict with the `id` value of any existing row, the `UPSERT` statement inserts a new row into the table. {% include copy-clipboard.html %} ~~~ sql > SELECT * FROM accounts; ~~~ ~~~ +----+----------+ | id | balance | +----+----------+ | 1 | 10000.5 | | 2 | 20000.75 | +----+----------+ ~~~ {% include copy-clipboard.html %} ~~~ sql > UPSERT INTO accounts (id, balance) VALUES (3, 6325.20); ~~~ {% include copy-clipboard.html %} ~~~ sql > SELECT * FROM accounts; ~~~ ~~~ +----+----------+ | id | balance | +----+----------+ | 1 | 10000.5 | | 2 | 20000.75 | | 3 | 6325.2 | +----+----------+ ~~~ ### Upsert multiple rows In this example, the `UPSERT` statement inserts multiple rows into the table. {% include copy-clipboard.html %} ~~~ sql > SELECT * FROM accounts; ~~~ ~~~ +----+----------+ | id | balance | +----+----------+ | 1 | 10000.5 | | 2 | 20000.75 | | 3 | 6325.2 | +----+----------+ ~~~ {% include copy-clipboard.html %} ~~~ sql > UPSERT INTO accounts (id, balance) VALUES (4, 1970.4), (5, 2532.9), (6, 4473.0); ~~~ {% include copy-clipboard.html %} ~~~ sql > SELECT * FROM accounts; ~~~ ~~~ +----+----------+ | id | balance | +----+----------+ | 1 | 10000.5 | | 2 | 20000.75 | | 3 | 6325.2 | | 4 | 1970.4 | | 5 | 2532.9 | | 6 | 4473.0 | +----+----------+ ~~~ ### Upsert that updates a row (conflict on primary key) In this example, the `id` column is the primary key. Because the inserted `id` value is not unique, the `UPSERT` statement updates the row with the new `balance`. {% include copy-clipboard.html %} ~~~ sql > SELECT * FROM accounts; ~~~ ~~~ +----+----------+ | id | balance | +----+----------+ | 1 | 10000.5 | | 2 | 20000.75 | | 3 | 6325.2 | | 4 | 1970.4 | | 5 | 2532.9 | | 6 | 4473.0 | +----+----------+ ~~~ {% include copy-clipboard.html %} ~~~ sql > UPSERT INTO accounts (id, balance) VALUES (3, 7500.83); ~~~ {% include copy-clipboard.html %} ~~~ sql > SELECT * FROM accounts; ~~~ ~~~ +----+----------+ | id | balance | +----+----------+ | 1 | 10000.5 | | 2 | 20000.75 | | 3 | 7500.83 | | 4 | 1970.4 | | 5 | 2532.9 | | 6 | 4473.0 | +----+----------+ ~~~ ### Upsert that fails (conflict on non-primary key) `UPSERT` will not update rows when the uniquness conflict is on columns not in the primary key. In this example, the `a` column is the primary key, but the `b` column also has the [`UNIQUE` constraint](unique.html). Because the inserted `b` value is not unique, the `UPSERT` fails. {% include copy-clipboard.html %} ~~~ sql > SELECT * FROM unique_test; ~~~ ~~~ +---+---+ | a | b | +---+---+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +---+---+ ~~~ {% include copy-clipboard.html %} ~~~ sql > UPSERT INTO unique_test VALUES (4, 1); ~~~ ~~~ pq: duplicate key value (b)=(1) violates unique constraint "unique_test_b_key" ~~~ In such a case, you would need to use the [`INSERT ON CONFLICT`](insert.html) statement to specify the `b` column as the column with the `UNIQUE` constraint. {% include copy-clipboard.html %} ~~~ sql > INSERT INTO unique_test VALUES (4, 1) ON CONFLICT (b) DO UPDATE SET a = excluded.a; ~~~ {% include copy-clipboard.html %} ~~~ sql > SELECT * FROM unique_test; ~~~ ~~~ +---+---+ | a | b | +---+---+ | 2 | 2 | | 3 | 3 | | 4 | 1 | +---+---+ ~~~ ### Import data containing duplicate rows using `DISTINCT ON` If the input data to insert/update contains duplicate rows, you must use [`DISTINCT ON`](select-clause.html#eliminate-duplicate-rows) to ensure there is only one row for each value of the primary key. For example: {% include copy-clipboard.html %} ~~~ sql > WITH -- the following data contains duplicates on the conflict column "id": inputrows AS (VALUES (8, 130), (8, 140)) UPSERT INTO accounts (id, balance) (SELECT DISTINCT ON(id) id, balance FROM inputrows); -- de-duplicate the input rows ~~~ The `DISTINCT ON` clause does not guarantee which of the duplicates is considered. To force the selection of a particular duplicate, use an `ORDER BY` clause: {% include copy-clipboard.html %} ~~~ sql > WITH -- the following data contains duplicates on the conflict column "id": inputrows AS (VALUES (8, 130), (8, 140)) UPSERT INTO accounts (id, balance) (SELECT DISTINCT ON(id) id, balance FROM inputrows ORDER BY balance); -- pick the lowest balance as value to update in each account ~~~ {{site.data.alerts.callout_info}} Using `DISTINCT ON` incurs a performance cost to search and eliminate duplicates. For best performance, avoid using it when the input is known to not contain duplicates. {{site.data.alerts.end}} ## See also - [Ordering of rows in DML statements](query-order.html#ordering-rows-in-dml-statements) - [Selection Queries](selection-queries.html) - [`DELETE`](delete.html) - [`INSERT`](insert.html) - [`UPDATE`](update.html) - [`TRUNCATE`](truncate.html) - [`ALTER TABLE`](alter-table.html) - [`DROP TABLE`](drop-table.html) - [`DROP DATABASE`](drop-database.html) - [Other SQL Statements](sql-statements.html)