I have a table in SQL containing a column in JSON format. Here is a sample of the SQL query output:
I need for each row in this table to expand the JSON objects and values into new columns with the respective data included.
Example for the first row would be one new column named "rate" and its value would be "0.25", while for the second row other columns should be created named "from","to","fixed" and the respective values should be stored in two separate rows keeping the rest of the info identical as is in the query itself.
The complexity here is each row on the dataset has different information stored in the "Data Value" column (JSON data).
Is there any way I could use a query or any other method to do this?
EDIT:
Adding my SELECT statement for reference adding a new column for each object, but this does not work for arrays.
SELECT
port.id as "Port ID",
port.name as "Port Name",
country.name as "Country",
port_expense.id as "Port Expense ID",
port_expense.name::text as "Port Expense",
terminal.id as "Terminal ID",
terminal.name as "Terminal Name",
berth.id as "Berth ID",
berth.name as "Berth Name",
port_expense_formula_data.name as "Data Name",
port_expense_formula_data.value as "Data Value"
-- port_expense_formula_data.value::jsonb->>'from' as "From",
-- port_expense_formula_data.value::jsonb->>'to' as "To",
-- port_expense_formula_data.value::jsonb->>'unmoor' as "Unmoor",
-- port_expense_formula_data.value::jsonb->>'var' as "Var",
-- port_expense_formula_data.value::jsonb->>'tariff' as "Tariff",
-- port_expense_formula_data.value::jsonb->>'rate' as "Rate",
-- port_expense_formula_data.value::jsonb->>'lumpsum' as "Lumpsum",
-- port_expense_formula_data.value::jsonb->>'max' as "Max",
-- port_expense_formula_data.value::jsonb->>'min' as "Min",
-- port_expense_formula_data.value::jsonb->>'charge' as "Charge",
-- port_expense_formula_data.value::jsonb->>'day' as "Day",
-- port_expense_formula_data.value::jsonb->>'night' as "Night"
and a sample of the output:
3
Answers
First flatten the table using jsonb_array_elements to unnest the JSON array and a lateral join in order to produce a row per array element.
cross join lateral
is the verbose syntax. It can be replaced by, lateral
or – in the case of a set-returning function as above – just a comma.You may simulate/experiment with this example:
First, you need to differentiate whether jsonb column contains a single json or array of jsons. Therefore, I’d do something like:
You’re looking for the
jsonb_array_elements
table function to work with arrays. However, your data is extra challenging because you are storing a mix of objects and arrays-of-objects, try to avoid that if possible. So I’d first wrap the objects in an array usingjsonb_typeof
andjsonb_build_array
:or to access the
obj
properties:However, to extract JSON properties into columns, I recommend to use records via
jsonb_to_recordset
instead ofjsonb_array_elements
, which also lets you easily choose the column type: