Get Id from a conditional INSERT

前端 未结 2 673
醉话见心
醉话见心 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:20

    For a single row insert and no update:

    with i as (
        insert into users (name)
        select 'the name'
        where not exists (
            select 1
            from users
            where name = 'the name'
        )
        returning id
    )
    select id
    from users
    where name = 'the name'
    
    union all
    
    select id from i
    

    The manual about the primary and the with subqueries parts:

    The primary query and the WITH queries are all (notionally) executed at the same time

    Although that sounds to me "same snapshot" I'm not sure since I don't know what notionally means in that context.

    But there is also:

    The sub-statements in WITH are executed concurrently with each other and with the main query. Therefore, when using data-modifying statements in WITH, the order in which the specified updates actually happen is unpredictable. All the statements are executed with the same snapshot

    If I understand correctly that same snapshot bit prevents a race condition. But again I'm not sure if by all the statements it refers only to the statements in the with subqueries excluding the main query. To avoid any doubt move the select in the previous query to a with subquery:

    with s as (
        select id
        from users
        where name = 'the name'
    ), i as (
        insert into users (name)
        select 'the name'
        where not exists (select 1 from s)
        returning id
    )
    select id from s
    union all
    select id from i
    

提交回复
热议问题