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 :-)
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'
)
)
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
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
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