ANSI Casting Timestamp Netezza - convert SQL from Teradata - sql

I currently do not know ANSI equivalent to Teradata FORMAT key word for converting timestamp, date data types into our required representation formats. I know this can be done with to_char, to_date like individual database specific functions, But I want to write in ANSI so that in future I can easily move code running from one DB to another. Below is the current Teradata SQL I am trying to convert into ANSI so that I can run it on both Teradata ,Netezza and Vertica etc.
SELECT
CAST( (MYTIME ( FORMAT 'DDMMYYYY')) AS CHAR( 8 ))
|| CAST( (MYTIME (FORMAT 'HHMISS')) AS CHAR(6))
|| CAST(CAST(MYNUMBER AS FORMAT'-9(5)') AS CHAR(5))
FROM MYTABLE
;
Currently I don't know how to translate the FORMAT 'HHMISS', FORMAT '-9(5)' into ANSI. Is there any documentation on this possible ANSI equivalent functions if any? Please help.

You can try the EXTRACT() function. YMMV, but most modern RDBMS's support it. There's really no good answer here - every DBMS handles "date formatting" issues differently and confusingly.
select
case when extract(day from current_timestamp) < 10 then '0' else '' end || cast(extract(day from current_timestamp) as varchar(2)) ||
case when extract(month from current_timestamp) < 10 then '0' else '' end || cast(extract(month from current_timestamp) as varchar(2)) ||
cast(extract(year from current_timestamp) as varchar(4)) ||
case when extract(hour from current_timestamp) < 10 then '0' else '' end || cast(extract(hour from current_timestamp) as varchar(2)) ||
case when extract(minute from current_timestamp) < 10 then '0' else '' end || cast(extract(minute from current_timestamp) as varchar(2)) ||
case when extract(second from current_timestamp) < 10 then '0' else '' end || cast(extract(second from current_timestamp) as varchar(2))

In Teradata you should be able to do the following:
/* The double cast is to truncate any time value associated with MyTime */
SELECT CAST(CAST(MyTime AS DATE) AS TIMESTAMP(6))
+ ((MyTime - TIME '00:00:00') HOUR to SECOND(6)) AS MyTimeStamp_
FROM MyTable;
Another option to try:
SELECT CreateTimeStamp
, CAST((CreateTimeStamp (TIMESTAMP(6), FORMAT 'DDMMYYYYBHHMISS.S(6)')) AS CHAR(22)) AS MyTimeStamp_
, CAST((CreateTimeStamp (TIMESTAMP(6), FORMAT 'DD-MM-YYYYBHH:MI:SS.S(6)')) AS CHAR(26)) AS MyTimeStamp2_
FROM DBC.Databases
WHERE DatabaseName = USER;
My experience has been that you have to treat dates and timestamps differently with each database. One solution may not be universally accepted. But I'd love to see something that works in Teradata, Oracle, SQL Server, MySQL, etc.

Related

teradata converting timestamp to time

I'm struggling with something that seems very obvious on first sight and most probably I'm overlooking something stupid but anyway.
I need to calculate the difference between timestamp fields and convert the result (which is as I assume a timestamp ) into the number of days and the elapsed time.
I can't seem to get the cast(xx to time) wright
I made a small example
SELECT
Cast(Cast( c_date AS CHAR(10)) || ' ' || Cast( c_time AS CHAR(10)) AS TIMESTAMP(6)) AS starttime ,
Cast(Cast( e_date AS CHAR(10)) || ' ' || Cast( e_time AS CHAR(10)) AS TIMESTAMP(6)) AS endtm,
(endtm - starttime) DAY(4) TO SECOND AS difftime
,Extract(DAY From difftime) --> gives the days
,Cast(difftime AS TIME)
,Extract (HOUR From difftime)
FROM (
SELECT Cast(Current_Timestamp AS DATE) c_date,
Cast(Current_Timestamp(0) AS TIME(0)) c_time,
Cast(Current_Timestamp + Random(1,10) * INTERVAL '1' DAY AS DATE) e_date,
Cast(Current_Timestamp(0) + Random(1,24) * INTERVAL '1' HOUR + Random(1,60) * INTERVAL '1' MINUTE AS TIME(0)) e_time
) t
,Cast(difftime AS TIME) gives me the trouble
the extract day and hour works => the difftime is really a timestamp (is it ? and if not what kind of field is it then ? ).
some advise would be nice :-)

Converting time strings to appropriate format and perform arithmetic over them in Sqllite

I have data in an sqlite database where the timestamps are text in the form 10:15:28 PM and 9:43:43 PM.
How can I convert them to timestamps?
In SQLite, you need to use string functions to convert the values to something the database can understand as a time. For these AM/PM dates, one option is to turn the first 8 characters to a time, and add 12 hours to values that end with 'PM'.
time(
substr(mycol, 1, 8),
'+' || case when mycol like '%PM' then '12' else '0' end || 'hour'
)
From there on, you can use date functions. Say you want the difference between times in mycol1 and mycol2 in seconds, then:
strftime(
'%s',
time(
substr(mycol1, 1, 8),
'+' || case when mycol1 like '%PM' then '12' else '0' end || 'hour'
)
) - strftime(
'%s',
time(
substr(mycol1, 1, 8),
'+' || case when mycol1 like '%PM' then '12' else '0' end || 'hour'
)
)

Varchar m/d/yyyy to yyyy/mm/dd sql

I have a file that inputs data in the format m/d/yyyy or m/dd/yyyy depending on whether or not the date value is 2 digits (example 4/1/2015 or 4/14/2015). I need to convert this to a date with the format yyyy/mm/dd (example 2015/04/01 or 2015/04/14). I have tried multiple way but I get the error "Invalid date" every time. Please help.
Things I have tried:
cast((CASE WHEN CHAR_LENGTH(RSA_dt) <10 THEN 0 || TRIM(RSA_dt) end) AS DATE)
CAST( CAST( RSA_dt AS DATE FORMAT 'DD-MMM-YY') AS DATE FORMAT 'YYYY-MM-DD')
cast(RSA_dt as date format 'YYYY-MM-DD')
Which tool do you use for loading?
The easiest way to load this data is to define that column as a VARDATE in a TPT job:
VARDATE(10) FORMATIN 'MM/DD/YY' FORMATOUT 'YYYY-MM-DD'
Otherwise you got a problem as Teradata's CAST doesn't like single digit day/month. Starting with TD14 there's Oracle's TO_DATE, which still doesn't like a single digit month, but at least tolerates single digit day:
TO_DATE(CASE
WHEN RSA_dt LIKE '_/%'
THEN '0' || RSA_dt
ELSE RSA_dt
END
,'mm/dd/yyyy')
This will work for TPT.
Select '1/1/2014' as date1,
TO_DATE (
case
when strtok(date1, '/', 1) between 1 and 9 and strtok(date1, '/', 2) between 1 and 9 then strtok(date1,'/', 3)||'/0'||strtok(date1, '/', 1)||'/0'||strtok(date1,'/', 2)
when strtok(date1, '/', 1) between 1 and 9 and strtok(date1, '/', 2) > 9 then strtok(date1,'/', 3)||'/0'||strtok(date1, '/', 1)||'/'||strtok(date1,'/', 2)
when strtok(date1, '/', 1) > 9 and strtok(date1, '/', 2) between 1 and 9 then strtok(date1,'/', 3)||'/'||strtok(date1, '/', 1)||'/0'||strtok(date1,'/', 2)
else strtok(date1, '/', 3)||'/'||strtok(date1, '/', 1)||'/'||strtok(date1,'/', 2)
end , 'YYYY/MM/DD') as req_date
Here's another solution. It uses a regular expression to add a leading zero to any single-digit number, then standard casting to convert it to a date using existing format, then back to standard format. I have included several examples:
SELECT CAST(CAST(TD_SYSFNLIB.REGEXP_REPLACE('4/1/2015','(?<!\d)(\d)(?!\d)','0\1',1,0,'i') AS DATE FORMAT 'MM/DD/YYYY') AS DATE FORMAT 'YYYY-MM-DD');
SELECT CAST(CAST(TD_SYSFNLIB.REGEXP_REPLACE('4/14/2015','(?<!\d)(\d)(?!\d)','0\1',1,0,'i') AS DATE FORMAT 'MM/DD/YYYY') AS DATE FORMAT 'YYYY-MM-DD');
SELECT CAST(CAST(TD_SYSFNLIB.REGEXP_REPLACE('12/1/2015','(?<!\d)(\d)(?!\d)','0\1',1,0,'i') AS DATE FORMAT 'MM/DD/YYYY') AS DATE FORMAT 'YYYY-MM-DD');
It looks like you're providing the format you want, instead of the format you've got. Try this instead:
cast(RSA_dt as date format 'MM/DD/YYYY')
If you aren't using TPT, then you're stuck playing some awful substring games.
SELECT
SUBSTR(chardate,INSTR(chardate,'/',1,2)+ 1,4) AS theYear,
'00' || SUBSTR(chardate,1,INSTR(chardate,'1',1,1)-2) AS theMonth,
'00' || SUBSTR(chardate,INSTR(chardate,'/',1,1)+ 1,INSTR(chardate,'/',1,2) - INSTR(chardate,'/',1,1)-1) AS theDate,
CAST (theYear || '-' || SUBSTRING(theMonth,LENGTH(theMonth) -1,2) || '-' || SUBSTR(theDate,LENGTH(thedate)-1,2) AS DATE) AS ItsADate
FROM
<yourtable>
Really ugly, but it should work.
This should work.
Select '1/2/2014' as date1,
TO_CHAR(TO_DATE (
case
when strtok(date1, '/', 2) between 1 and 9 then strtok(date1,'/', 3)||'/0'||strtok(date1, '/', 1)||'/'||strtok(date1,'/', 2)
else strtok(date1, '/', 3)||'/'||strtok(date1, '/', 1)||'/'||strtok(date1,'/', 2)
end , 'YYYY/MM/DD'), 'YYYY/MM/DD') as "YYYY/MM/DD"
This will work, though not pretty. Specifically converting M/D/YYYY to YYYYMMDD
select substr(YOURDATE,-4,4) ||
substr('00'||SUBSTR(YOURDATE,1,to_number(regexp_instr(YOURDATE,'\/'))-1),-2,2) ||
case when substr(YOURDATE,2,1) = '/' then
case when substr(YOURDATE,4,1) = '/' then
'0' || substr(YOURDATE,3,1)
else substr(YOURDATE,3,2)
end
else case when substr(YOURDATE,5,1) = '/' then
'0' || substr(YOURDATE,4,1)
else substr(YOURDATE,4,2)
end
end as NEWDATE
from YOURTABLE

Postgres INTERVAL using value from table

If I want to add 5 days to a date, I can do it using the INTERVAL function:
select create_ts + interval '5 days' from abc_company;
However, my table has a field called num_of_days and I want to add it to my create_ts. Something like this:
select create_ts + interval num_of_days || ' days' from abc_company;
This does not work. How can I accomplish this in postgresql?
Simply multiply the value with an interval:
select create_ts + num_of_day * interval '1' day
from abc_company;
Since Postgres 9.4 this is easier done using the make_interval() function:
select create_ts + make_interval(days => num_of_day)
from abc_company;
You just need a working type cast. This kind is standard SQL.
select current_timestamp + cast((num_of_days || ' days') as interval)
from abc_company;
This is an alternative syntax, peculiar to PostgreSQL.
select current_timestamp + (num_of_days || ' days')::interval
from abc_company;
I prefer not trying to remember the third kind of type cast supported by PostgreSQL, which is the function-like syntax.
select current_timestamp + "interval" (num_of_days || ' days')
from abc_company;
Why? Because some function names have to be quoted; interval is one of them.
Also, the names interval, time, and timestamp can only be used in this
fashion if they are double-quoted, because of syntactic conflicts.
Therefore, the use of the function-like cast syntax leads to
inconsistencies and should probably be avoided.
here is a function that I use:
CREATE OR REPLACE FUNCTION DateAdd(diffType varchar(15), incrementValue int, inputDate timestamp) RETURNS timestamp AS $$
DECLARE
YEAR_CONST Char(15) := 'year';
MONTH_CONST Char(15) := 'month';
WEEK_CONST Char(15) := 'week';
DAY_CONST Char(15) := 'day';
HOUR_CONST Char(15) := 'hour';
dateTemp timestamp;
intervals interval;
BEGIN
IF lower($1) = lower(YEAR_CONST) THEN
select cast(cast(incrementvalue as character varying) || ' year' as interval) into intervals;
ELSEIF lower($1) = lower(MONTH_CONST) THEN
select cast(cast(incrementvalue as character varying) || ' months' as interval) into intervals;
ELSEIF lower($1) = lower(DAY_CONST) THEN
select cast(cast(incrementvalue as character varying) || ' day' as interval) into intervals;
ELSEIF lower($1) = lower(WEEK_CONST) THEN
select cast(cast(incrementvalue as character varying) || ' week' as interval) into intervals;
ELSEIF lower($1) = lower(HOUR_CONST) THEN
select cast(cast(incrementvalue as character varying) || ' hour' as interval) into intervals;
END IF;
dateTemp := inputdate + intervals;
RETURN dateTemp;
END;
$$ LANGUAGE plpgsql;
Used like so:
select dateadd('day', 3, current_timestamp);
It supports adding years, months, weeks, days, hours. More support could be added

DB2 date conversion

I have 2 INTEGER columns like the following:
Month Year
----- -----
5 2011
Is there any way to convert that to a single column VARCHAR like this: May-2011
I don't know of an easy way to do this since you don't have a date object (ie its not like youre finding the month of a timestamp), you can use a case statement but it gets long.
SELECT CASE Month
WHEN '1' THEN 'January'
WHEN '2' THEN 'February'
WHEN '3' THEN 'March'
WHEN '4' THEN 'April'
...
END+'-'+Year
FROM TABLE
I think this will do it:
SELECT
MONTHNAME(
DATE(CAST(Year AS CHAR(4)) || '-' || TRIM(CAST(Month AS CHAR(2))) || '-1')
) || '-' || CAST(Year AS CHAR(4))
FROM TABLE
This should do the trick, assuming that the columns Month and Year are integers and Month has the domain 1-12:
select substring('---JanFebMarAprMayJunJulAugSepOctNovDec', 3*Month , 3 )
+ '-'
+ right(digits(Year),4)
from some_table
If Month is 0 you'll get '---' as the month; if it's less than 0 or greater than 12, you'll get some sort of blooey.
You could create a function to convert the month value, like this...
CREATE FUNCTION INT2MONTH (MONTH INTEGER)
RETURNS VARCHAR(100)
LANGUAGE SQL
CONTAINS SQL
NO EXTERNAL ACTION
DETERMINISTIC
RETURN MONTHNAME('2000-' || RIGHT('0' || STRIP(CHAR(MONTH)), 2) || '-01')
Then you can...
select int2month(month) || '-' || strip(char(year)) from test
1
--------------------------------------------------
May-2011
June-2011
December-2012
If you want a 3 char month then change last last on function to...
RETURN LEFT(MONTHNAME('2000-' || RIGHT('0' || STRIP(CHAR(MONTH)), 2) || '-01'), 3)
I realize this question is pretty old, but there's a way that is a lot simpler than any of the options listed here (in my opinion) -- a combination of some date math and the VARCHAR_FORMAR() function:
SELECT
VARCHAR_FORMAT(
DATE('0001-01-01') + (month_col - 1) MONTH + (year_col - 1) YEAR
,'Month-YYYY'
)
FROM your_table