'How to update a table without creating new rows

Imagine I have a set of key-value data from a primary key to values:

id foo
1 abc
2 def
3 ghj

... that need to be updated in a table.

And I want to update all of these in one query. Naturally, upserts come to mind, which works quite well:

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

This works fine, but what if I don't actually want to insert the row with id=3 when it doesn't already exist in the table my_table?



Solution 1:[1]

One thing I have already tried (and it works) is to use a source query which receives all of the source data as a json list and then inner joins to the existing table to throw away all the records that don't have an entry in my_table:

[
  {"id": 1, "foo": "abc"},
  {"id": 2, "foo": "def"},
  {"id": 3, "foo": "ghj"}
]

which is passed as the only parameter to this query:

WITH source AS (
SELECT my_table.id, x.foo FROM jsonb_to_recordset($1::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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 narrowtux