I have the following table defined in Postgres (version 12.12):
Table "public.test"
Column | Type | Collation | Nullable | Default
-----------+-------+-----------+----------+---------
uuid | uuid | | |
name | text | | |
json_data | jsonb | | |
Here is a sample row:
uuid | name | json
12345678-3ffd-472b-ac39-31eacc4a6785 | foo | {"id": 1132}
I want to update json_data using a value from a different column in the same table. Something like this:
UPDATE test SET json_data = json_data || '{"xyz":{"enabled": false, "uuid": test.uuid}}';
where the value of uuid is the "uuid" value from the same row. So, I would like the desired updated row to look like this:
uuid | name | json
12345678-3ffd-472b-ac39-31eacc4a6785 | foo | {"id": 1132, "xyz":{"enabled": false, "uuid": "12345678-3ffd-472b-ac39-31eacc4a6785"}}
Tried this, but got a syntax error:
UPDATE test SET json_data = json_data || '{"xyz":{"enabled": false, "uuid": test.uuid}}';
ERROR: invalid input syntax for type json
LINE 1: update test set json_data = json_data || '{"xyz":{"e...
^
DETAIL: Token "test" is invalid.
CONTEXT: JSON data, line 1: {"xyz":{"enabled": false, "uuid": test...
2
Answers
You can’t put an SQL expression like
test.uuid
in a literal and expect it to be evaluated. You could use string interpolation and casts, but that’s ugly and easy to mess up.Rather, build the json(b) value using the
jsonb_build_object
function:Alternatively, you could use
jsonb_set
instead of concatenation:However this is rather ugly, I would recommend it only when setting a single property.
Because you use json instead of jsonb, you need a little casting to use the json-functions for updating json content:
Now you don’t need any text functions and you’re safe when you have some NULL’s in some column. Because
results in a NULL