views:

471

answers:

3

I have a need to change the length of CHAR columns in tables in a PostgreSQL v7.4 database. This version did not support the ability to directly change the column type or size using the ALTER TABLE statement. So, directly altering a column from a CHAR(10) to CHAR(20) for instance isn't possible (yeah, I know, "use varchars", but that's not an option in my current circumstance). Anyone have any advice/tricks on how to best accomplish this? My initial thoughts:

-- Save the table's data in a new "save" table. CREATE TABLE save_data AS SELECT * FROM table_to_change;

-- Drop the columns from the first column to be changed on down. ALTER TABLE table_to_change DROP column_name1; -- for each column starting with the first one that needs to be modified ALTER TABLE table_to_change DROP column_name2; ...

-- Add the columns back, using the new size for the CHAR column ALTER TABLE table_to_change ADD column_name1 CHAR(new_size); -- for each column dropped above ALTER TABLE table_to_change ADD column_name2...

-- Copy the data bace from the "save" table UPDATE table_to_change SET column_name1=save_data.column_name1, -- for each column dropped/readded above column_name2=save_date.column_name2, ... FROM save_data WHERE table_to_change.primary_key=save_data.primay_key;

Yuck! Hopefully there's a better way? Any suggestions appreciated. Thanks!

+1  A: 

I would dump the table contents to a flat file with COPY, drop the table, recreate it with the correct column setup, and then reload (with COPY again).

http://www.postgresql.org/docs/7.4/static/sql-copy.html

Is it acceptable to have downtime while performing this operation? Obviously what I've just described requires making the table unusable for a period of time, how long depends on the data size and hardware you're working with.

Edit: But COPY is quite a bit faster than INSERTs and UPDATEs. According to the docs you can make it even faster by using BINARY mode. BINARY makes it less compatible with other PGSQL installs but you won't care about that because you only want to load the data to the same instance that you dumped it from.

Nate C-K
I thought of doing a drop/create table like that, but I was hoping to not have to drop it, since I then need to regrant all permissions. This operation needs to happen on about 50 servers, each with its own database, users, etc., so the hope was to make an SQL update script that could be run on each. I suppose I could save the pg_class.relacl value for the table and reset it after the drop/add to get the permissions back.
E Brown
Yeah, that does sound like a pain. You could also export the table's setup with pg_dump. With that you should be able to script out all of the commands that need to be applied to that table and then rerun them after you recreate the table. Your temp table solution might end up being simpler, though.
Nate C-K
FWIW, my job is developing a system that maintains database tables and the approaches we use for this case are the one that you've described and the one that I've described. COPY (or whatever bulk loader your RDBMS uses) is faster but a temp table is less instrusive.
Nate C-K
+1  A: 

Not PostgreSQL, but in Oracle I have changed a column's type by:

  1. Add a new column with a temporary name (ie: TMP_COL) and the new data type (ie: CHAR(20))
  2. run an update query: UPDATE TBL SET TMP_COL = OLD_COL;
  3. Drop OLD_COL
  4. Rename TMP_COL to OLD_COL
Graham
Another good approach, although it results in relocating the column position in the table schema. I would need to check if this table ever receives an ASCII file load for instance where the column positions are relevant.
E Brown
+1  A: 

The best approach to your problem is to upgrade pg to something less archaic :)

Seriously. 7.4 is going to be removed from "supported versions" pretty soon, so I wouldn't wait for it to happen with 7.4 in production.

depesz
Sigh...I know, but also not an option currently :( I remember using the even more archaic Informix-SE back in the late 80's that supported ALTER TABLE that could change column type/size in place. Shame that the PostgreSQL folks couldn't do the same circa 2003 or whatever it was for v7.4. Oh well.
E Brown
I'm sure you could have your money back.
Milen A. Radev
Yeah, I know, it's free, and I love PostgreSQL. But still, seems like pretty basic functionality for the DDL to be missing in a v7+ release.
E Brown