Reputation: 1509
I have a table in my database that needs to be restructured. It currently looks like this:
id | attrs
----+--------------------------------------------------------------------------------------
1 | {"type": "test_type", "m_attrs": {"left_values": "Jack", "right_values": "John"}}
However I am wanting to alter this table and split the attrs
column into separate columns for type
, left_values
and right_values
:
alter table t_name add column if not exists type text;
alter table t_name add column if not exists left_values text;
alter table t_name add column if not exists right_values text;
What is the best way to make these columns not null and have their default value set to the value in the existing attrs column, ie:
attrs->m_attrs->>'left_value'
The table is very large in terms of rows so I'm wary of performance issues too.
Upvotes: 1
Views: 581
Reputation: 247865
From PostgreSQL v12 on, it would be best to use generated columns:
ALTER TABLE t_name
ADD "type" text GENERATED ALWAYS AS (attrs->>'type') STORED,
ADD left_values text GENERATED ALWAYS AS (attrs->'m_attrs'->>'left_values') STORED,
ADD right_values text GENERATED ALWAYS AS (attrs->'m_attrs'->>'right_values') STORED;
This will require a table rewrite, so it will take some time and space, but there is no way to avoid a table rewrite with an operation like that anyway. You can reduce the impact by doing it in a single ALTER TABLE
as above.
For older database versions, you have to do it in steps:
UPDATE
NOT NULL
if desiredApart from providing atomicity, the transaction makes sure that no new rows are added before the trigger is in place.
After that, it might be good to VACUUM (FILL)
the table (still more down time) to get rid of the bloat from the UPDATE
.
Upvotes: 2