Get Id from a conditional INSERT

前端 未结 2 689
醉话见心
醉话见心 2021-01-04 17:46

For a table like this one:

CREATE TABLE Users(
    id SERIAL PRIMARY KEY,
    name TEXT UNIQUE
);

What would be the correct one-

2条回答
  •  刺人心
    刺人心 (楼主)
    2021-01-04 18:25

    The UPSERT implementation is hugely complex to be safe against concurrent write access. Take a look at this Postgres Wiki that served as log during initial development. The Postgres hackers decided not to include "excluded" rows in the RETURNING clause for the first release in Postgres 9.5. They might build something in for the next release.

    This is the crucial statement in the manual to explain your situation:

    The syntax of the RETURNING list is identical to that of the output list of SELECT. Only rows that were successfully inserted or updated will be returned. For example, if a row was locked but not updated because an ON CONFLICT DO UPDATE ... WHERE clause condition was not satisfied, the row will not be returned.

    Bold emphasis mine.

    For a single row to insert:

    Without concurrent write load on the same table

    WITH ins AS (
       INSERT INTO users(name)
       VALUES ('new_usr_name')         -- input value
       ON     CONFLICT(name) DO NOTHING
       RETURNING users.id
       )
    SELECT id FROM ins
    UNION  ALL
    SELECT id FROM users          -- 2nd SELECT never executed if INSERT successful
    WHERE  name = 'new_usr_name'  -- input value a 2nd time
    LIMIT  1;
    

    With possible concurrent write load on the table

    Consider this instead (for single row INSERT):

    • Is SELECT or INSERT in a function prone to race conditions?

    To insert a set of rows:

    • How to use RETURNING with ON CONFLICT in PostgreSQL?

    • How to include excluded rows in RETURNING from INSERT ... ON CONFLICT

    All three with very detailed explanation.

提交回复
热议问题