We’re changing a column run_dates (per request) from daterange to tstzrange, a column with a few months of test data. Essentially we want to migrate!
I’m running the script below, inspired by postgreSQL alter column data type to timestamp without time zone and I have to admit, my SQL background is basically nothing
-- Create a temporary TIMESTAMP column ALTER TABLE table_name ADD COLUMN run_dates_holder TSTZRANGE NULL; -- Copy casted value over to the temporary column UPDATE table_name SET run_dates_holder = run_dates::TSTZRANGE; -- Modify original column using the temporary column ALTER TABLE table_name ALTER COLUMN run_dates TYPE TSTZRANGE USING run_dates_holder; -- Drop the temporary column (after examining altered column values) ALTER TABLE table_name DROP COLUMN run_dates_holder;
Unfortunately….. These types don’t naturally translate.
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) cannot cast type daterange to tstzrange
and
psycopg2.ProgrammingError: cannot cast type daterange to tstzrange LINE 5: ...ble_name SET run_dates_holder = run_dates::TSTZRANG...
Has anyone ever successfully migrated a daterange to a tstzrange?
As a backup, we can def just drop the daterange column and recreate as tstzrange, since that would only affect test data. Just less optimal for the team. It’s worth a shot to look into this, and I think the resolution here is at least worthwhile to future ‘daterange-to-tstzrange’ migrators, as I found no other docs/resources on the matter
Advertisement
Answer
You can’t just cast a daterange to a tstzrange. Use lower() and upper() to extract the bounds of the daterange and upper_inc() and lower_inc() to extract their inclusivity, and construct a new tstzrange.
UPDATE table_name
SET run_dates_holder=tstzrange(
lower(run_dates), upper(run_dates),
concat(
CASE WHEN lower_inc(run_dates) THEN '[' else '(' END,
CASE WHEN upper_inc(run_dates) THEN ']' ELSE ')' END)
);