I have a table books
:
Name of column | Type |
---|---|
id | int (PK) |
name | text |
nb_pages | int |
And a table book_modifications
:
Name of column | Type |
---|---|
id | int (PK) |
old_data | jsonb |
new_data | jsonb |
book_id | int (FK) |
Now let's imagine I have a row in my books
table like this :
id: 15,
name: "name-1",
nb_pages: 120
And a row to insert in my book_modifications
table like this :
id: 7,
old_data: {name: "name-1", nb_pages: 120},
new_data: {name: "new-name-1"},
book_id: 15
My question is :
How can I update my books
table with the new_data
column of my book_modifications
table in SQL or PostgreSQL ?
Currently I have found this way :
create or replace function on_book_modifications_insert ()
returns trigger
language plpgsql
as $$
begin
-- Here (new_data only contains the 'name' field)
UPDATE books
SET name = new.new_data -> 'name', nb_pages = new.new_data -> 'nb_pages'
WHERE id = new.book_id;
return new;
end;
$$
In this case, the SQL query above will update nb_pages
to null
because it is not present in new_data
(which will generate an error), whereas I would like to leave nb_pages
at 120 and only update fields present in new_data
.
For INSERT, I've seen that json_object
exists, but I can't find it for UPDATE.
You can just use COALESCE
against the original value. If the JSONB value doesn't exist then you get null, which is replaced with the original, so effectively a no-op.
create or replace function on_book_modifications ()
returns trigger
language plpgsql
as $$
begin
-- Here (new_data only contains the 'name' field)
UPDATE books
SET
name = COALESCE(new.new_data ->> 'name', books.name),
nb_pages = COALESCE((new.new_data ->> 'nb_pages')::int, books.nb_pages)
WHERE books.id = new.book_id;
return new;
end;
$$