如何在不创建新行的情况下更新 table

How to update a table without creating new rows

假设我有一组从主键到值的键值数据:

id foo
1 abc
2 def
3 ghj

...需要在 table.

中更新

我想在一个查询中更新所有这些。自然而然地,upserts 浮现在脑海中,效果很好:

INSERT INTO my_table (id, foo) VALUES ((1, 'abc'), (2, 'def'), (3, 'ghj')) 
ON CONFLICT (id) DO UPDATE SET foo = excluded.foo;

这很好用,但是如果我实际上不想插入 id=3 的行,因为它不存在于 table my_table 中怎么办?

我已经尝试过(并且有效)的一件事是使用源查询,它接收所有源数据作为 json 列表,然后内部连接到现有的 table 到丢弃所有在 my_table:

中没有条目的记录
[
  {"id": 1, "foo": "abc"},
  {"id": 2, "foo": "def"},
  {"id": 3, "foo": "ghj"}
]

作为此查询的唯一参数传递:

WITH source AS (
SELECT my_table.id, x.foo FROM jsonb_to_recordset(::jsonb) AS x(id int, foo text)
JOIN my_table ON x.id = my_table.id
)
INSERT INTO my_table (id, foo) 
(SELECT * FROM source) 
ON CONFLICT(id) DO UPDATE SET foo = excluded.foo

如果您只想更新行,我完全不明白为什么您需要 INSERT?

update my_table 
  set foo = v.foo 
from ( 
  VALUES (1, 'abc'), (2, 'def'), (3, 'ghj')
) as v(id, foo)
where v.id = my_table.id;