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?
CodePudding user response:
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 |
... 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.