简体   繁体   中英

postgres: update a row on conflict insert and return old values

I need a query to update a row in table, but if the id doesn't exist it inserts default values. Also it has to avoid threads race conditions.

I found an answer here that should be fine https://stackoverflow.com/a/7927957/8372336

Using this query:

UPDATE tbl x
SET    tbl_id = 24
     , name = 'New Gal'
FROM  (SELECT tbl_id, name FROM tbl WHERE tbl_id = 4 FOR UPDATE) y 
WHERE  x.tbl_id = y.tbl_id
RETURNING y.tbl_id AS old_id, y.name AS old_name, x.tbl_id, x.name;

So I think it should return old values after updating and it should prevent threads race conditions.

But I need to add an insert if the row doesn't exist and also return the inserted values this time (old values doesn't make sense because they didn't exist).

So basically I need to do something like

INSERT INTO tbl 
    (...) VALUES (...) 
    RETURNING ..., ... 
ON CONFLICT DO
UPDATE tbl x
SET    tbl_id = 24
     , name = 'New Gal'
FROM  (SELECT tbl_id, name FROM tbl WHERE tbl_id = 4 FOR UPDATE) y 
WHERE  x.tbl_id = y.tbl_id
RETURNING y.tbl_id AS old_id, y.name AS old_name, x.tbl_id, x.name;

but i'm not sure if something like this could work. how can i make it work and make it sure of race conditions?

Somehow, this seems to work:

insert into t (x)
    values ('a0'), ('b')
    on conflict (x) do update
        set x = excluded.x || '0'
    returning i, x, (select x from t t2 where t2.i = t.i);

I am surprised because t is in scope in the subquery, but excluded is not. Hmmm . . . perhaps that is because it is not part of the on conflict clause but part of the overall insert . That starts to make sense.

Here is a db<>fiddle for this version.

I think your code would look like:

INSERT INTO tbl (...)
    VALUES (...) 
ON CONFLICT DO
UPDATE tbl x
    SET tbl_id = 24,
        name = 'New Gal'
RETURNING (SELECT t2.tbl_id FROM tbl t2 WHERE t2.tbl_id = tbl.tbl_id) AS old_id, 
          (SELECT t2.name FROM tbl t2 WHERE t2.tbl_id = tbl.tbl_id) AS old_name, 
          x.tbl_id, x.name;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM