PostgreSQL alter column type from DATERANGE to TSTZRANGE and migrate the data - sql

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

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)
);

Using the line from AdamKG's answer (selected as the BEST!) we arrive at this
-- -- Create a placeholder tstzrange column
ALTER TABLE SB ADD COLUMN run_dates_holder tstzrange NULL;
-- -- Update placeholder tstzrange column with existing run_dates
UPDATE SB SET run_dates_holder=tstzrange(lower(run_dates), upper(run_dates),'[)');
-- -- Remove original run_dates
ALTER TABLE SB DROP COLUMN run_dates;
-- -- Rename 'run_dates_holder' to 'run_dates'
ALTER TABLE SB RENAME COLUMN run_dates_holder to run_dates;
Test data's remained intact

Related

Converting date column to varchar column in Oracle with existing data

I need to change column type from DATE to VARCHAR2. Currently, date column has so many records which are inserted previously and now I need to change column type from DATE to VARCHAR2 without losing any existing data. Please suggest me how can I do it?
simple demostration:
create table t (c date);
insert into t values (sysdate);
alter table t add c_tmp varchar2(20);
update t set c_tmp = c;
alter table t drop column c;
alter table t rename column c_tmp to c;
drop table t;
however, I don't recommend for most of the circumstances to convert data type from date to varchar2. It does not provide clear benefit on my point of view.

Convert column from varchar to datetime and update it in the table

I have a question related to the conversion of varchar to datetime.
This topic was covered already in the thread
SQL Server Convert Varchar to Datetime
but I would like to advance it bit further.
I have performed BULK INSERT into predefined tables where VARCHAR(255)
is the destination. I have a table dbo.USR_02_ALL_RAW and the field GLTGB which
holds strings in the following format: 07/16/2016.
I can convert it as a single string by the following code:
DECLARE #Date varchar(255)
set #Date= '07/16/2016'
SELECT CONVERT(datetime,RIGHT(#Date,4)+LEFT(#Date,2)+SUBSTRING(#Date,4,2))
and it gives me a result:
2016-07-16 00:00:00.000
However I would like to pass to the code the whole field GLTGB from the table
dbo.USR_02_ALL_RAW, convert it from VARCHAR into DATETIME and update the field GLTGB with these results.(converting the whole field from varchar to datetime)
Thank you!
First clear this, you want to Bulk insert or Bulk update. Since you already have a column GLTGB. If you want to update the value only.
update tab set GLTGB =
CONVERT(datetime,RIGHT(GLTGB,4)+LEFT(GLTGB,2)+SUBSTRING(GLTGB,4,2))
Or
If you want to update the field from varchar to datetime. Then process is little bit lengthy.
Alter table tab add newcol datetime --- Add new datetime type column
update tab set newcol =
CONVERT(datetime,RIGHT(GLTGB,4)+LEFT(GLTGB,2)+SUBSTRING(GLTGB,4,2)) --- update value in new column
Alter table tab drop column GLTGB --- drop GLGTB column
Alter table tab add GLGTB datetime --- add GLGTB column as datetime type
update tab set GLGTB = newcol --- update value from GLGTB from newcol
Alter table tab drop column newcol ---- remove unnecessary newcol
If you convert a value to datetime, then update the same database column it came from with the value then, since that column is still varchar, SQL will have to convert the value back to varchar again in order to store it. So you can't achieve anything useful with that kind of simple approach.
f you want to actually change the data type of the column, and also convert all the values, then I think you need to go through the following process:
1) Create a new varchar column in your table (which will be temporary)
2) copy all the data values from the GLTGB column into the new column (using an UPDATE statement)
3) Drop the GLTGB column
4) Re-create it with the same name but with datetime type
5) Use an UPDATE statement to re-populate the new GLTGB column from your temporary column
6) Finally, drop the temporary column
There may be a simpler way but that seems like the obvious process.
You can use the following code for updating but before that, you need to change the data type of your field to DateTime
update dbo.USR_02_ALL_RAW
set GLTGB=cast(CONVERT(datetime,RIGHT(#Date,4)+LEFT(#Date,2)+SUBSTRING(#Date,4,2)) as datetime)

Convert datetime column to smallint

I have a column called MyYear that is of type datetime. It only stores the year though, so I want to change it to smallint.
When I try to run this:
ALTER TABLE MyTable
ALTER COLUMN MyYear smallint
I get this error:
Implicit conversion from data type datetime to smallint is not
allowed. Use the CONVERT function to run this query.
When I run this:
UPDATE MyTable
set MyYear=YEAR(MyYear)
It does something funky and sets all the years to 1905.
I am using SQL Server.
You cannot convert a DATETIME to a SMALLINT, you will need to:
ALTER TABLE MyTable
ADD MyActualYear SMALLINT
GO
UPDATE MyTable SET MyActualYear = CAST(YEAR(MyYear) AS SMALLINT)
GO
ALTER TABLE MyTable
DROP COLUMN MyYear
GO
EXEC sp_RENAME 'MyTable.[MyActualYear]' , 'MyYear', 'COLUMN'
GO
i.e. add a new temporary column, update it with the value you need, drop the old column and then rename the temp column with the original name.
If you have indexes on this column, you may want to bear in mind any impact this might have.

Convert varchar to date in sql loader

I have loaded the date field with dates and type is varchar.
How to convert date field(varchar) to date field(date) in oracle express/sql loader while displaying the fields?
You can't change the data type of a column in a permanent table from VARCHAR2 to DATE when it has data.
You can, however, add a new column
ALTER TABLE table_name
ADD( new_date_column DATE );
move the data over
UPDATE table_name
SET new_date_column = to_date( old_varchar2_column, format_mask );
drop the old column
ALTER TABLE table_name
DROP COLUMN old_varchar2_column;
and then rename the new column to the old column name
ALTER TABLE table_name
RENAME COLUMN new_date_column TO old_column_name
Of course, once you do this, you'll need to change your SQL*Loader script to convert the data to a DATE if you ever want to load into this table again.

Alter character field to date

I've a legacy postgres db that has date columns cast as character(50) fields (don't ask). I'd like to alter the table and columns to contain actual dates. Because this worked:
select distinct to_date(date_begin, 'YYYY DD MM') from dates;
I naively thought this might work:
alter table dates alter column date_begin type character
using to_date(date_begin, 'YYYY DD MM');
But it does not. Any clues for the clueless?
This just works as intended by the OP. What we have here is a simple thinko/typo.
Read more in the manual about ALTER TABLE.
Demo:
-- DROP SCHEMA x CASCADE;
CREATE SCHEMA x;
CREATE TABLE x.tbl(date_begin character(50));
INSERT INTO x.tbl VALUES ('2011-11-11 11:11'), (NULL), (''), ('1977');
-- NULL and empty string work too
-- even just YYYY works: '1977' .. is converted to '1977-01-01' automatically
-- empty string produce a possibly surprising result: '0001-01-01 BC'
ALTER TABLE x.tbl ALTER COLUMN date_begin TYPE date USING to_date(date_begin, 'YYYY DD MM');
SELECT * FROM x.tbl;
Hint: You wrote type character instead of type date.
It will take three stages:
1) Alter the table to add the date column.
2) Run an update query which converts each string date into the date field
3) Alter the table to remove the text date column.