Return rows from INSERT with ON CONFLICT without needing to update

ira

I have a situation where I very frequently need to get a row from a table with a unique constraint, and if none exists then create it and return. For example my table might be:

CREATE TABLE names(
    id SERIAL PRIMARY KEY,
    name TEXT,
    CONSTRAINT names_name_key UNIQUE (name)
);

And it contains:

id | name
 1 | bob 
 2 | alice

Then I'd like to:

 INSERT INTO names(name) VALUES ('bob')
 ON CONFLICT DO NOTHING RETURNING id;

Or perhaps:

 INSERT INTO names(name) VALUES ('bob')
 ON CONFLICT (name) DO NOTHING RETURNING id

and have it return bob's id 1. However, RETURNING only returns either inserted or updated rows. So, in the above example, it wouldn't return anything. In order to have it function as desired I would actually need to:

INSERT INTO names(name) VALUES ('bob') 
ON CONFLICT ON CONSTRAINT names_name_key DO UPDATE
SET name = 'bob'
RETURNING id;

which seems kind of cumbersome. I guess my questions are:

  1. What is the reasoning for not allowing the (my) desired behaviour?

  2. Is there a more elegant way to do this?

Erwin Brandstetter

It's the recurring problem of SELECT or INSERT, related to (but different from) an UPSERT. The new UPSERT functionality in Postgres 9.5 is still instrumental.

WITH ins AS (
   INSERT INTO names(name)
   VALUES ('bob')
   ON     CONFLICT ON CONSTRAINT names_name_key DO UPDATE
   SET    name = NULL
   WHERE  FALSE      -- never executed, but locks the row
   RETURNING id
   )
SELECT id FROM ins
UNION  ALL
SELECT id FROM names
WHERE  name = 'bob'  -- only executed if no INSERT
LIMIT  1;

This way you do not actually write a new row version without need.

I assume you are aware that in Postgres every UPDATE writes a new version of the row due to its MVCC model - even if name is set to the same value as before. This would make the operation more expensive, add to possible concurrency issues / lock contention in certain situations and bloat the table additionally.

However, there is still a tiny corner case for a race condition. Concurrent transactions may have added a conflicting row, which is not yet visible in the same statement. Then INSERT and SELECT come up empty.

Proper solution for single-row UPSERT:

General solutions for bulk UPSERT:

Without concurrent write load

If concurrent writes (from a different session) are not possible you don't need to lock the row and can simplify:

WITH ins AS (
   INSERT INTO names(name)
   VALUES ('bob')
   ON     CONFLICT ON CONSTRAINT names_name_key DO NOTHING  -- no lock needed
   RETURNING id
   )
SELECT id FROM ins
UNION  ALL
SELECT id FROM names
WHERE  name = 'bob'  -- only executed if no INSERT
LIMIT  1;

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

Postgres INSERT ON CONFLICT DO UPDATE vsINSERTまたはUPDATE

分類Dev

Return INSERT output from a function

分類Dev

PostgreSql Having conflict between group by and needing to add two more columns

分類Dev

Postgres INSERT ON CONFLICT with JSONB

分類Dev

MySQL INSERT INTO from PHP://INPUT multiple rows

分類Dev

JLabel not refreshing without needing additional threads?

分類Dev

Store update, insert, or delete statement affected an unexpected number of rows (0).

分類Dev

Insert content from a temporary table into an update query

分類Dev

How to return rows of data from a table with json?

分類Dev

Return random set of rows from a REGEXP query

分類Dev

INSERT INTO after CONCAT data from different columns from different rows

分類Dev

PostgreSQL INSERT ON CONFLICT UPDATE(upsert)はすべての除外値を使用します

分類Dev

Insert multiple rows from two tables into one table

分類Dev

How to use a Twitter stream source in Hazelcast Jet without needing a DAG?

分類Dev

Keeping QPlainTextEdit as small as possible without needing a scroll bar

分類Dev

Running a DHCP server without conflict

分類Dev

What is the best way to use the insert, delete and update from an Content Provider?

分類Dev

how to insert and update data into postgresql from node js using if condition

分類Dev

OWIN Store update, insert, or delete statement affected an unexpected number of rows (0) Error

分類Dev

Oracle SQL to return column values from unique rows

分類Dev

How to select a list but return rows from an Oracle database

分類Dev

Return multiple rows from table to Rails controller action

分類Dev

SQL Server insert EXCEPT without selecting from a table

分類Dev

Insert 2 rows in tables with foreign key relation without knowing the primary key of the main table

分類Dev

Cleaning up files from table without deleting rows in postgresql 9.6.3

分類Dev

Asp Core1.1でのAPIREST Update / Insert / Delete return

分類Dev

Needing react-native features from master branch

分類Dev

Postgres INSERT ON CONFLICT DO NOTHING vs SELECT + INSERT query

分類Dev

Return JsonResult from web api without its properties

Related 関連記事

  1. 1

    Postgres INSERT ON CONFLICT DO UPDATE vsINSERTまたはUPDATE

  2. 2

    Return INSERT output from a function

  3. 3

    PostgreSql Having conflict between group by and needing to add two more columns

  4. 4

    Postgres INSERT ON CONFLICT with JSONB

  5. 5

    MySQL INSERT INTO from PHP://INPUT multiple rows

  6. 6

    JLabel not refreshing without needing additional threads?

  7. 7

    Store update, insert, or delete statement affected an unexpected number of rows (0).

  8. 8

    Insert content from a temporary table into an update query

  9. 9

    How to return rows of data from a table with json?

  10. 10

    Return random set of rows from a REGEXP query

  11. 11

    INSERT INTO after CONCAT data from different columns from different rows

  12. 12

    PostgreSQL INSERT ON CONFLICT UPDATE(upsert)はすべての除外値を使用します

  13. 13

    Insert multiple rows from two tables into one table

  14. 14

    How to use a Twitter stream source in Hazelcast Jet without needing a DAG?

  15. 15

    Keeping QPlainTextEdit as small as possible without needing a scroll bar

  16. 16

    Running a DHCP server without conflict

  17. 17

    What is the best way to use the insert, delete and update from an Content Provider?

  18. 18

    how to insert and update data into postgresql from node js using if condition

  19. 19

    OWIN Store update, insert, or delete statement affected an unexpected number of rows (0) Error

  20. 20

    Oracle SQL to return column values from unique rows

  21. 21

    How to select a list but return rows from an Oracle database

  22. 22

    Return multiple rows from table to Rails controller action

  23. 23

    SQL Server insert EXCEPT without selecting from a table

  24. 24

    Insert 2 rows in tables with foreign key relation without knowing the primary key of the main table

  25. 25

    Cleaning up files from table without deleting rows in postgresql 9.6.3

  26. 26

    Asp Core1.1でのAPIREST Update / Insert / Delete return

  27. 27

    Needing react-native features from master branch

  28. 28

    Postgres INSERT ON CONFLICT DO NOTHING vs SELECT + INSERT query

  29. 29

    Return JsonResult from web api without its properties

ホットタグ

アーカイブ