Reputation: 143114
It often happens that the original name something is given is not the best name. Maybe requirements shifted slightly, or maybe as time went on, a better understanding of the concept being represented developed. Sometimes one name is used in developing a feature, but testing with real users reveals that a better name is needed, and it'd be nice to have the names for things in the DB match the names used in the UI.
PostgreSQL lets you rename tables and columns via alter table
, but often this isn't feasible in production without significant downtime. If existing clients are using the old name, you can't just yank it out from under them.
I was hoping there was some way to "add a name" to a table or column, so that old_name
and new_name
will both work, and then at a later time remove the old name. Then a name migration could work like this:
new_name
new_name
instead of old_name
old_name
Is there a way to do this? If not, is there a recommended procedure for renaming a column while minimizing downtime? How about a table?
Upvotes: 20
Views: 10515
Reputation: 143114
Some recipes for renaming tables and/or columns in a production system that seem to work. However, I've only tested these on a small test database, not on a large production system. Renaming and view creation are both supposed to be very fast, though.
Rename the table, and temporarily add an updatable view with the old name:
begin;
alter table old_table_name rename to new_table_name;
create view old_table_name as
select * from new_table_name;
commit;
Migrate clients to use the new table name.
Once all clients are migrated, drop the view:
drop view old_table_name;
Renaming a column without renaming the table is a bit more complicated, because we can't have a view shadow a table (apparently).
Rename the column(s), temporarily rename the table, and add an updatable view that adds the old name for the column with the table's correct name:
begin;
alter table my_table rename column old_column_name to new_column_name;
alter table my_table rename to my_table_tmp;
create view my_table as
select *, new_column_name as old_column_name
from my_table_tmp;
commit;
Migrate clients to use the new column name.
Once all clients are migrated, drop the view, rename the table back:
begin;
drop view my_table;
alter table my_table_tmp rename to my_table;
commit;
Rename the table and columns, and temporarily add an updatable view with the old name and old columns:
begin;
alter table old_table_name
rename to new_table_name;
alter table new_table_name
rename column old_column_name to new_column_name;
create view old_table_name as
select *, old_column_name as new_column_name
from new_table_name;
commit;
Instead of select *, old_column_name as new_column_name
, it might be better to only have
the original set of columns, so clients have to migrate to the new table
name to get the new column names:
create view old_table_name as
select
unchanged_name1,
unchanged_name2,
...
old_column_name as new_column_name
from new_table_name;
Migrate clients to use the new table and column names.
Once all clients are migrated, drop the view:
drop view old_table_name;
Upvotes: 23