postgres:更新冲突插入行和 return 旧值
postgres: update a row on conflict insert and return old values
我需要一个查询来更新 table 中的一行,但如果 ID 不存在,它会插入默认值。它还必须避免线程竞争条件。
我在这里找到了答案应该没问题
使用此查询:
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;
所以我认为它应该 return 更新后的旧值并且它应该防止线程竞争条件。
但是如果该行不存在我需要添加一个插入,而且这次 return 插入的值(旧值没有意义,因为它们不存在)。
所以基本上我需要做一些类似
的事情
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;
但我不确定这样的事情是否可行。我怎样才能让它工作并确保竞争条件?
不知何故,这似乎有效:
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);
我很惊讶,因为 t
在子查询的范围内,但 excluded
不在。嗯。 . .也许那是因为它不是 on conflict
子句的一部分,而是整个 insert
的一部分。这开始有意义了。
Here 是此版本的 db<>fiddle。
我认为您的代码如下所示:
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;
我需要一个查询来更新 table 中的一行,但如果 ID 不存在,它会插入默认值。它还必须避免线程竞争条件。
我在这里找到了答案应该没问题
使用此查询:
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;
所以我认为它应该 return 更新后的旧值并且它应该防止线程竞争条件。
但是如果该行不存在我需要添加一个插入,而且这次 return 插入的值(旧值没有意义,因为它们不存在)。
所以基本上我需要做一些类似
的事情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;
但我不确定这样的事情是否可行。我怎样才能让它工作并确保竞争条件?
不知何故,这似乎有效:
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);
我很惊讶,因为 t
在子查询的范围内,但 excluded
不在。嗯。 . .也许那是因为它不是 on conflict
子句的一部分,而是整个 insert
的一部分。这开始有意义了。
Here 是此版本的 db<>fiddle。
我认为您的代码如下所示:
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;