I want to convert a VARCHAR2-value like '-28:15:00' to INTERVAL.
With a literal value, this works:
select interval '-09:11:36' hour to second from dual;
However, this does not (ORA-00923: FROM keyword not found where expected):
select interval MY_VARCHAR hour to second from MY_TABLE;
--comparable to select interval to_char(sysdate, 'hh:mm:ss') hour to second from dual;
My assumption is that the literal value is implicitly cast while the explicit varchar-value from MY_VARCHAR (or char from to_char respectively) is not valid between "interval" and "hour".
CAST like this does not work (ORA-00963: unsupported interval type):
select cast(MY_VARCHAR as interval hour to second) from MY_TABLE;
--comparable to select cast('09:11:36' as interval hour to second) from dual;
What does work is concatenating '0 ' as the day-value and cast it to INTERVAL DAY TO SECOND:
select cast('0 ' || '09:11:36' as interval day to second) from dual;
However this only works for positive values, and as long as the value for hour is below 24.
Is there a better solution than dissecting the VARCHAR-value with CASE, SUBSTR and so on?
You need the minus sign before the days to cast it to an interval:
SELECT value,
CAST( REGEXP_REPLACE(value, '^(-)?', '\10 ') AS INTERVAL DAY TO SECOND )
AS interval_value
FROM table_name
or, using simple string functions, which slightly more to type but probably more efficient (as regular expressions are slow):
SELECT value,
CAST(
CASE
WHEN value LIKE '-%'
THEN '-0 ' || SUBSTR(value, 2)
ELSE '0 ' || value
END
AS INTERVAL DAY TO SECOND
) AS interval_value
FROM table_name
Which, for the sample data:
CREATE TABLE table_name (value) AS
SELECT '-09:11:36' FROM DUAL UNION ALL
SELECT '09:11:36' FROM DUAL;
Both output:
VALUE
INTERVAL_VALUE
-09:11:36
-00 09:11:36.000000
09:11:36
+00 09:11:36.000000
fiddle
Another approach, which would accept hour values greater than 23, is to coerce the string into ISO format and use the to_dsinterval() function:
select my_varchar,
to_dsinterval(
regexp_replace(my_varchar, '(-?)(\d+):(\d+):(\d+)', '\1PT\2H\3M\4S')
) as interval_value
from my_table
MY_VARCHAR
INTERVAL_VALUE
-09:11:36
-000000000 09:11:36.000000000
09:11:36
+000000000 09:11:36.000000000
28:15:02
+000000001 04:15:02.000000000
-28:15:02
-000000001 04:15:02.000000000
fiddle
You could do reformatting of the string with string functions, which as #MTO mentioned will be faster for large amounts of data, but it would be a bit messy:
select my_varchar,
to_dsinterval(
case
when substr(my_varchar, 1, 1) = '-'
then '-PT' || substr(my_varchar, 2, instr(my_varchar, ':', 1, 1) - 2)
else 'PT' || substr(my_varchar, 1, instr(my_varchar, ':', 1, 1) - 1)
end || 'H'
|| substr(my_varchar, instr(my_varchar, ':', 1, 1) + 1,
instr(my_varchar, ':', 1, 2) - instr(my_varchar, ':', 1, 1) - 1) || 'M'
|| substr(my_varchar, instr(my_varchar, ':', 1, 2) + 1) || 'S'
) as interval_value
from my_table
MY_VARCHAR
INTERVAL_VALUE
-09:11:36
-000000000 09:11:36.000000000
09:11:36
+000000000 09:11:36.000000000
28:15:02
+000000001 04:15:02.000000000
-28:15:02
-000000001 04:15:02.000000000
fiddle
As shown in the documentation, interval literals (like all literals, as the name implies) require a fixed value, not an expression or column; the quotes are not optional in the railroad diagram:
... so your first query gets ORA-00923.
And the cast() function only supports certain conversions:
Note 1: Datetime/interval includes DATE, TIMESTAMP, TIMESTAMP WITH TIMEZONE, TIMESTAMP WITH LOCAL TIME ZONE, INTERVAL DAY TO SECOND, and INTERVAL YEAR TO MONTH.
so you can't cast(... as interval hour to second), and that will throw ORA-00963.
Related
I've tried this approach but keep getting errors. A value in the hour_column would look like this: 15. The date_column looks like this: 2021-09-24
cast(date_column as time) + INTERVAL '1 HOUR' * cast(hour_column as time)
I understood that you just need to set only the hour value (hour gets from column) on the DateTime column of the table.
Sample Query:
with table1 as (
select '2022-04-06 08:19:54.230' as pdatetime, '12' as phour
union all
select '2022-04-06 14:47:11.412' as pdatetime, '18' as phour
union all
select '2022-04-06 20:26:37.106' as pdatetime, '22' as phour
)
select
pdatetime::timestamp -
(extract(hour from pdatetime::timestamp)::text || ' hour')::interval +
(phour || ' hour')::interval
from table1
-- Return:
2022-04-06 12:19:54.230
2022-04-06 18:47:11.412
2022-04-06 22:26:37.106
I have a data set with the following columns
time date
1310 2020-06-01
1425 2020-06-22
1640 2020-06-29
My desired final output is a column in datetime format that looks as such
datetime
2020-06-01 13:10:00.000
2020-06-22 14:25:00.000
2020-06-29 16:40:00.000
I have used the following command thus far to format the output the way I would like
CONCAT(date_string, ' ', substring(barstarttime, 1, 2), ':', substring(barstarttime, 3, 2), ':00.000'))
However, I have not had success in changing this to a datetime or timestamp.
Is there a function that can help me do so?
Thanks
Get the hours and minutes from the time string with SUBSTR. Then add the according intervals to the date.
I don't know whether Presto allows functions for the interval values. Please try:
select
date +
interval substr(time, 1, 2) hour +
interval substr(time, 3, 2) minute
from mytable;
If this doesn't work, try this instead:
select
date +
((interval '1' hour) * cast(substr(time, 1, 2) as integer)) +
((interval '1' minute) * cast(substr(time, 3, 2) as integer))
from mytable;
As mentioned, I don't know Presto. You may even have to cast the date to a timestamp first:
cast(date as timestamp) +
...
You can use date_parse function.
select date_parse(cast(date as varchar) || ' ' || time, '%Y-%m-%d %H%i') from
(values ('1300', date '2020-06-01')) as t(time, date)
You can use below in order to convert to timestamp
select *,
cast(date_col as timestamp) as ts
from T
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 date field in oracle which returns
17-APR-19 12:00:00 AM
I also have a time column (VARCHAR) which returns HHMM in Military
1810
I'd like to combine these two fields to create a timestamp that is formatted to RFC 3339 standards. Preferable like this.
2019-04-17T18:10:00Z
I can convert a timestamp into the correct time using this:
SELECT
TO_CHAR(
SYSTIMESTAMP AT TIME ZONE 'UTC',
'yyyy-mm-dd"T"hh24:mi:ss"Z"'
)
FROM dual;
Is there a way to convert my date and time field into this timestamp format? The time on the date field is incorrect and needs to be replaced by the time field.
You can TRUNCate your date back to midnight and then use NUMTODSINTERVAL to add hours and minutes to it to get the correct time component:
Oracle Setup:
CREATE TABLE your_table ( your_date_column, your_time_column ) AS
SELECT DATE '2019-04-17', '1810' FROM DUAL
Query:
SELECT TO_CHAR(
TRUNC( your_date_column )
+ NUMTODSINTERVAL( SUBSTR( your_time_column, 1, 2 ), 'HOUR' )
+ NUMTODSINTERVAL( SUBSTR( your_time_column, 3, 2 ), 'MINUTE' ),
'YYYY-MM-DD"T"HH24:MI:SS"Z"'
) AS combined_date_time
FROM your_table
Output:
| COMBINED_DATE_TIME |
| :------------------- |
| 2019-04-17T18:10:00Z |
db<>fiddle here
If you want the value as a TIMESTAMP WITH TIME ZONE then:
SELECT CAST(
TRUNC( your_date_column )
+ NUMTODSINTERVAL( SUBSTR( your_time_column, 1, 2 ), 'HOUR' )
+ NUMTODSINTERVAL( SUBSTR( your_time_column, 3, 2 ), 'MINUTE' )
AS TIMESTAMP
) AT TIME ZONE 'UTC' AS combined_date_time
FROM your_table
Just do a bit of string concatenation
to_char( your_date, 'yyyy-mm-dd' ) ||
'T' ||
substr( your_time, 1, 2 ) ||
':' ||
substr( your_time, 3, 2 ) ||
':00Z'
assuming that your_time is always 4 characters long (i.e. 2 AM is represented as the string '0200' rather than '200'). This also assumes that the seconds will always be '00'.
You can achieve this by converting your_number into minutes and add it to your date, then cast it to timestamp as following:
SELECT CAST(
your_date +
(FLOOR(YOUR_TIME/100)*60 + MOD(YOUR_TIME,100)) / 1440
AS TIMESTAMP
) AT TIME ZONE 'UTC' AS YOUR_TIME_STAMP
FROM your_table;
Cheers!!
I'd like to format a number as "1st", "2nd", "4th", "9th", etc. Is there an Oracle function that will do this for me?
Assuming the value supplied is numeric, rather than DATE, you can use TO_CHAR but you have to convert the numeric value to a string, then a DATE (Julian) before ultimately formatting it:
SELECT TO_CHAR(TO_DATE('1', 'dd'), 'ddth')
FROM DUAL
Result:
01st
When testing, using 'd' for the format didn't return expected results because the value is interpreted as a Julian date. Either substring the output to remove the leading zero, or provide a full date string (doesn't matter to the TO_CHAR because it's only interested in the day of the month):
SELECT TO_CHAR(TO_DATE('1900-01-01', 'YYYY-MM-dd'), 'dth')
FROM DUAL
Because calendar days end at 31, use the year value instead to handle numbers greater than 31:
SELECT TO_CHAR(TO_DATE('32-01-01', 'YYYY-MM-dd'), 'yyth')
FROM DUAL
Result:
32nd
Maybe I'm oversimplifying, but it seems like the following should work just fine (for integers) and is a lot more readable than converting to a date and back:
select case
when initial_extent is null then null
when substr(initial_extent,-2,1) = '1'
then initial_extent || 'th'
else case substr(initial_extent,-1,1)
when '1' then initial_extent || 'st'
when '2' then initial_extent || 'nd'
when '3' then initial_extent || 'rd'
else initial_extent || 'th'
end
end as formatted_number
from user_tables
select substr( to_char( to_date( abs( decode( mod( l_value, 10 ), 0, 4, mod( l_value , 10 ) ) ), 'YYYY' ), 'YTH' ), 2 ) as value
from dual
Replace l_value with appropriate, hmmm, value. Should cover any numbers.