How can we get the 15 minutes time interval - sql

I am trying to fetch every 15min data in such a way that, if the current time is 23-10-19 11:11:30 then I need to get the data from 23-10-19 10:30:59 to 23-10-19 10:45:59 in the same way if the time is 23-10-19 11:15:30 then I need to get the data from 23-10-19 10:45:59 to 23-10-19 11:00:59.
I have tried forgetting the 15min delay but not the way I want to approach. Please suggest me how can we approach the scenario
select concat(to_char(current_timestamp - numtodsinterval(30,'MINUTE'),'yyyy-mm-dd hh24:mi'),':59') A,
concat(to_char(current_timestamp - numtodsinterval(15,'MINUTE'),'yyyy-mm-dd hh24:mi'),':59') B,
to_char(current_timestamp,'yyyy-mm-dd hh24:mi:ss') C from dual
below is the output that I was getting.
A B C
------------------- ------------------- -------------------
2019-10-23 13:03:59 2019-10-23 13:18:59 2019-10-23 13:33:22

You can truncate to the nearest minute to zero the seconds and then subtract the number of minutes to get back to the nearest 15 minute interval past the hour and then apply your offsets:
SELECT TRUNC( current_timestamp, 'MI' )
- MOD( EXTRACT( MINUTE FROM current_timestamp ), 15 ) * INTERVAL '1' MINUTE
- INTERVAL '30' MINUTE
+ INTERVAL '59' SECOND AS start_time,
TRUNC( current_timestamp, 'MI' )
- MOD( EXTRACT( MINUTE FROM current_timestamp ), 15 ) * INTERVAL '1' MINUTE
- INTERVAL '15' MINUTE
+ INTERVAL '59' SECOND AS end_time,
current_timestamp
FROM DUAL
Outputs:
START_TIME | END_TIME | CURRENT_TIMESTAMP
:------------------ | :------------------ | :----------------------------
2019-10-23 09:00:59 | 2019-10-23 09:15:59 | 2019-10-23 09:42:53.742684000
db<>fiddle here

Another solution is this one:
WITH t AS
(SELECT TRUNC(CURRENT_TIMESTAMP , 'hh') + TRUNC(EXTRACT(MINUTE FROM CURRENT_TIMESTAMP ) / 15) * INTERVAL '15' MINUTE - INTERVAL '30' MINUTE AS Base
FROM dual)
SELECT Base + INTERVAL '59' SECOND AS begin_time,
Base + INTERVAL '15:59' minute to SECOND AS end_time
FROM t;
It is based on my generic Interval function:
CREATE OR REPLACE FUNCTION MakeInterval(ts IN TIMESTAMP, roundInterval IN INTERVAL DAY TO SECOND) RETURN TIMESTAMP DETERMINISTIC IS
denom INTEGER;
BEGIN
IF roundInterval >= INTERVAL '1' HOUR THEN
denom := EXTRACT(HOUR FROM roundInterval);
IF MOD(24, denom) <> 0 THEN
RAISE VALUE_ERROR;
END IF;
RETURN TRUNC(ts) + TRUNC(EXTRACT(HOUR FROM ts) / denom) * denom * INTERVAL '1' HOUR;
ELSIF roundInterval >= INTERVAL '1' MINUTE THEN
denom := EXTRACT(MINUTE FROM roundInterval);
IF MOD(60, denom) <> 0 THEN
RAISE VALUE_ERROR;
END IF;
RETURN TRUNC(ts, 'hh') + TRUNC(EXTRACT(MINUTE FROM ts) / denom) * denom * INTERVAL '1' MINUTE;
ELSE
denom := EXTRACT(SECOND FROM roundInterval);
IF MOD(60, denom) <> 0 THEN
RAISE VALUE_ERROR;
END IF;
RETURN TRUNC(ts, 'mi') + TRUNC(EXTRACT(SECOND FROM ts) / denom) * denom * INTERVAL '1' SECOND;
END IF;
END MakeInterval;
You would invoke it as
SELECT MakeInterval(CURRENT_TIMESTAMP, INTERVAL '15' MINUTE) from dual;
plus/minus your constant offsets.

select :start_date + (1/96)*(level-1) from dual connect by level < :intervals

Related

Oracle SQL Time Difference in hours

I'm trying to find a way to get the holiday hours while comparing two dates.
the query below at the moment excludes the holidays and returns the working hours. I'm struggling to get it the other way. Just to return number of hours of holidays which falls between start and end date.
If the start date is of 15-04-22 16:00 and its a holiday then query should only return hours b/w 16:00 - 18:00. (work hours would be between 7:00 - 18:00)
create table holidays_tb(
holiday_date date
);
insert into holidays_tb values (TO_DATE('15/04/2022', 'DD/MM/YYYY'));
insert into holidays_tb values (TO_DATE('18/04/2022', 'DD/MM/YYYY'));
declare
v_st_date date;
v_end_date date;
return_val number;
begin
v_st_date := TO_DATE('13/04/2022 09:55:52', 'DD/MM/YYYY HH24:MI:SS');
v_end_date := TO_DATE('19/04/2022 16:30:00', 'DD/MM/YYYY HH24:MI:SS');
with all_days as
(select trunc(v_st_date) + level - 1 as a_dt
from dual
connect by level <= 1 + (v_end_date - v_st_date)
minus
select holiday_date from holidays_tb
)
select sum (11)
into return_val
from all_days
where TO_CHAR ( a_dt , 'Dy') NOT IN ('Sat', 'Sun');
dbms_output.put_line( return_val );
end;
Have been stuck at it for more than couple of hours now :|
You can get the number of holiday hours using:
DECLARE
v_st_date date := DATE '2022-04-13' + INTERVAL '0 09:55:52' DAY TO SECOND;
v_end_date date := DATE '2022-04-19' + INTERVAL '0 16:30:00' DAY TO SECOND;
v_work_day_start INTERVAL DAY(0) TO SECOND(0) := INTERVAL '0 07:00:00' DAY TO SECOND;
v_work_day_end INTERVAL DAY(0) TO SECOND(0) := INTERVAL '0 18:00:00' DAY TO SECOND;
v_hours NUMBER := EXTRACT(HOUR FROM v_work_day_end - v_work_day_start)
+ EXTRACT(MINUTE FROM v_work_day_end - v_work_day_start)/60
+ EXTRACT(MINUTE FROM v_work_day_end - v_work_day_start)/3600;
v_holiday NUMBER;
return_val number;
BEGIN
SELECT SUM(
LEAST(holiday_date + v_work_day_end, v_end_date)
- GREATEST(holiday_date + v_work_day_start, v_st_date)
) * 24
INTO v_holiday
FROM holidays_tb
WHERE holiday_date BETWEEN TRUNC(v_st_date) AND v_end_date
AND holiday_date - TRUNC(holiday_date, 'IW') < 5;
DBMS_OUTPUT.PUT_LINE( v_holiday );
END;
/
Which, for the sample data, outputs 22.
Additionally, you do not need to use a recursive query to get the number of days and can directly calculate it using:
DECLARE
v_st_date date := DATE '2022-04-13' + INTERVAL '0 09:55:52' DAY TO SECOND;
v_end_date date := DATE '2022-04-19' + INTERVAL '0 16:30:00' DAY TO SECOND;
v_work_day_start INTERVAL DAY(0) TO SECOND(0) := INTERVAL '0 07:00:00' DAY TO SECOND;
v_work_day_end INTERVAL DAY(0) TO SECOND(0) := INTERVAL '0 18:00:00' DAY TO SECOND;
v_hours NUMBER := EXTRACT(HOUR FROM v_work_day_end - v_work_day_start)
+ EXTRACT(MINUTE FROM v_work_day_end - v_work_day_start)/60
+ EXTRACT(MINUTE FROM v_work_day_end - v_work_day_start)/3600;
v_holiday NUMBER;
return_val number;
BEGIN
SELECT SUM(
LEAST(holiday_date + v_work_day_end, v_end_date)
- GREATEST(holiday_date + v_work_day_start, v_st_date)
) * 24
INTO v_holiday
FROM holidays_tb
WHERE holiday_date BETWEEN TRUNC(v_st_date) AND v_end_date
AND holiday_date - TRUNC(holiday_date, 'IW') < 5;
return_val :=
-- Full weeks
(TRUNC(v_end_date, 'IW') - TRUNC(v_st_date, 'IW')) * 5 / 7 * v_hours
-- Full days before in start week
- LEAST(TRUNC(v_st_date) - TRUNC(v_st_date, 'IW'), 5) * v_hours
-- Part days before in start week
- CASE
WHEN v_st_date - TRUNC(v_st_date, 'IW') < 5
THEN LEAST(
GREATEST(
(v_st_date - (TRUNC(v_st_date) + v_work_day_start))* 24,
0
),
v_hours
)
ELSE 0
END
-- End full days
+ LEAST(TRUNC(v_end_date) - TRUNC(v_end_date, 'IW'), 5) * v_hours
-- End part days
+ CASE
WHEN v_end_date - TRUNC(v_end_date, 'IW') < 5
THEN LEAST(
GREATEST(
(v_end_date - (TRUNC(v_end_date) + v_work_day_start))* 24,
0
),
v_hours
)
ELSE 0
END
-- Holiday hours
- v_holiday;
DBMS_OUTPUT.PUT_LINE( return_val );
END;
/
Which outputs: 28.5689 (33 hours for 3 full days less 1.5 hours at the end and almost 3 hours at the start).

Inserting data into table with year dates and time in four column with dbms(range of time)

Hi dear I have a table with columns DT, DT2, DT3, DT4 I can insert in one column but not at all column same time please if you have any idea then told me thanks in advance my code is
insert into calendar_dateS4 (DT,DT2,DT3, DT4, DT5 )
SELECT DT, DT2, DT3, DT4, DT5
FROM (
SELECT DATE '2020-01-01' + FLOOR( (LEVEL - 1) )
+ INTERVAL '08:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE() * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '16:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE() * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '05:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE() * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '13:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE() * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '21:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE() * INTERVAL '00:15' HOUR TO MINUTE
AS DT, DT2, DT3, DT4, DT5
FROM DUAL
CONNECT BY
DATE '2020-01-01' + FLOOR( (LEVEL - 1) )
< ADD_MONTHS( DATE '2020-01-01', 12 )
)
Your INSERT is failing because your SELECT statement is not valid. Work on getting a valid SELECT statement with the results you want, then convert that into an INSERT statement.
To insert the same time into all 5 columns, you can use a statement like this:
INSERT INTO calendar_dateS4 (DT,
DT2,
DT3,
DT4,
DT5)
SELECT dt,
dt,
dt,
dt,
dt
FROM ( SELECT DATE '2020-01-01'
+ FLOOR ((LEVEL - 1))
+ INTERVAL '08:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE () * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '16:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE () * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '05:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE () * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '13:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE () * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '21:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE () * INTERVAL '00:15' HOUR TO MINUTE AS DT
FROM DUAL
CONNECT BY DATE '2020-01-01' + FLOOR ((LEVEL - 1)) < ADD_MONTHS (DATE '2020-01-01', 12))

Oracle Summarize data by 15 second interval

I want to summarize below query by 15 second time intervals.
select to_char(sample_time,'hh24:mi:ss') as SAMPLE_TIME,nvl(wait_class,'CPU'),count(*)
from gv$active_session_history
group by wait_class,sample_time;
Result;
SAMPLE_TIME WAITS COUNT
-----------------------------
14:59:00 CPU 3
14:59:02 CPU 1
14:59:08 CPU 2
14:58:11 CPU 2
14:59:18 CPU 1
14:59:24 CPU 2
14:58:29 CPU 2
What i want is summing values by 15 second intervals. How can i make it?
SAMPLE_TIME WAITS COUNT
-----------------------------
14:59:15 CPU 8
14:59:30 CPU 5
Use this function:
CREATE OR REPLACE FUNCTION MakeInterval(ts IN TIMESTAMP, roundInterval IN INTERVAL DAY TO SECOND) RETURN TIMESTAMP DETERMINISTIC IS
denom INTEGER;
BEGIN
IF roundInterval >= INTERVAL '1' HOUR THEN
denom := EXTRACT(HOUR FROM roundInterval);
IF MOD(24, denom) <> 0 THEN
RAISE VALUE_ERROR;
END IF;
RETURN TRUNC(ts) + TRUNC(EXTRACT(HOUR FROM ts) / denom) * denom * INTERVAL '1' HOUR;
ELSIF roundInterval >= INTERVAL '1' MINUTE THEN
denom := EXTRACT(MINUTE FROM roundInterval);
IF MOD(60, denom) <> 0 THEN
RAISE VALUE_ERROR;
END IF;
RETURN TRUNC(ts, 'hh') + TRUNC(EXTRACT(MINUTE FROM ts) / denom) * denom * INTERVAL '1' MINUTE;
ELSE
denom := EXTRACT(SECOND FROM roundInterval);
IF MOD(60, denom) <> 0 THEN
RAISE VALUE_ERROR;
END IF;
RETURN TRUNC(ts, 'mi') + TRUNC(EXTRACT(SECOND FROM ts) / denom) * denom * INTERVAL '1' SECOND;
END IF;
END MakeInterval;
Then you can use
...
GROUP BY wait_class, MakeInterval(SAMPLE_TIME, INTERVAL '15' SECOND)
-- can't add comments because my rep is very low
#Wernfried Domscheit gave you all the information required, I took his comments and simply "slapped" them in the group by part of your query (and obviously needed to add the bucket definition in the select statement)
The code below will allow you to check Wernfried's reply:
select TO_CHAR(TRUNC(SAMPLE_TIME, 'mi') + TRUNC(EXTRACT(SECOND FROM SAMPLE_TIME) /
EXTRACT(SECOND FROM INTERVAL '15' SECOND)) * EXTRACT(SECOND FROM INTERVAL '15'
SECOND) * INTERVAL '1' SECOND,'MM/DD/YYYY HH24:MI:SS') AS TimeBucket
, nvl(wait_class,'CPU')
,count(*) as NbrRecords
from gv$active_session_history
GROUP BY TO_CHAR(TRUNC(SAMPLE_TIME, 'mi') + TRUNC(EXTRACT(SECOND FROM SAMPLE_TIME) /
EXTRACT(SECOND FROM INTERVAL '15' SECOND)) * EXTRACT(SECOND FROM INTERVAL '15'
SECOND) * INTERVAL '1' SECOND,'MM/DD/YYYY HH24:MI:SS'), nvl(wait_class,'CPU')
ORDER BY TimeBucket DESC
;
HTH,
B
This looks a bit hack-ish but it should be what you are looking for. The lpad is just for a nicer looking result.
Edit: Forgot to group by the actual statement and not the sample_time. It should now group in 15 seconds intervals.
select
to_char(sample_time, 'hh24:mi:') || lpad(trunc(to_number(to_char(sample_time, 'ss')) / 15) * 15, 2, '0') as SAMPLE_TIME,
nvl(wait_class, 'CPU') as wait_class,
count(*)
from gv$active_session_history
group by nvl(wait_class, 'CPU'), to_char(sample_time, 'hh24:mi:') || lpad(trunc(to_number(to_char(sample_time, 'ss')) / 15) * 15, 2, '0')

Rounding to Previous 2 hour Window Oracle SQL

I'm trying to round a date (date datatype which includes timestamp too) to the previous 2 hour block. e.g 13:23 -> 12:00, 18:12 -> 18:00
I had it working in MySQL using a MOD function as:
DATE_ADD(DATE(DATE_ADD(created_at, INTERVAL - 7 HOUR)), INTERVAL HOUR(DATE_ADD(created_at, INTERVAL - 6 HOUR)) - MOD(HOUR(DATE_ADD(created_at, INTERVAL - 6 HOUR)), 2) HOUR) AS Window_Start
**Complexity added as I'm also shifting the time a) to correct for a 7 hr time zone difference and b) because I need to offset the time by 1 hr before grouping it. But that's not where the issue is.
But I can't get it to work on an Oracle platform. Specifically, I can't seem to extract the hour of the time as a number which to feed into the MOD(). I've been trying with CAST, and TO_TIMESTAMP and TO_CHAR but nothing seems to work. The usual error is "inconsistent datatypes".
EXTRACT only works with with timestamp type, not date. And TO_TIMESTAMP only works on strings. But EXTRACT(TO_TIMESTAMP(TO_CHAR( doesn't work either.
I'm sure there's an easier way to do this...
In Oracle, one method is using date arithmetic. For example:
select date '2000-01-01' + floor((sysdate - date '2000-01-01') * (24 / 2)) / (24 / 2)
from dual;
The "24" is for hours in a day. The "2" is for the two hour period you want to truncate to.
I'm not sure that this is the answer but it'll give you a rabbit hole to chase:
select sysdate as curr_dt, to_date(to_char(sysdate - interval '2' hour, 'yyyy-mm-dd HH24')) as two_hours_ago from dual;
Hope it helps!
To get the hour in a number format this will work.
select TO_NUMBER(TO_CHAR(SYSDATE,'HH')) from dual
You can select each piece individually using the time stamp portion of this date format DD/MM/YYYY HH:MI:SS.
Some time ago I wrote this generic function:
CREATE FUNCTION MakeInterval(ts IN TIMESTAMP, roundInterval IN INTERVAL DAY TO SECOND) RETURN TIMESTAMP DETERMINISTIC IS
denom INTEGER;
BEGIN
IF roundInterval >= INTERVAL '1' HOUR THEN
denom := EXTRACT(HOUR FROM roundInterval);
IF MOD(24, denom) <> 0 THEN
RAISE VALUE_ERROR;
END IF;
RETURN TRUNC(ts) + TRUNC(EXTRACT(HOUR FROM ts) / denom) * denom * INTERVAL '1' HOUR;
ELSIF roundInterval >= INTERVAL '1' MINUTE THEN
denom := EXTRACT(MINUTE FROM roundInterval);
IF MOD(60, denom) <> 0 THEN
RAISE VALUE_ERROR;
END IF;
RETURN TRUNC(ts, 'hh') + TRUNC(EXTRACT(MINUTE FROM ts) / denom) * denom * INTERVAL '1' MINUTE;
ELSE
denom := EXTRACT(SECOND FROM roundInterval);
IF MOD(60, denom) <> 0 THEN
RAISE VALUE_ERROR;
END IF;
RETURN TRUNC(ts, 'mi') + TRUNC(EXTRACT(SECOND FROM ts) / denom) * denom * INTERVAL '1' SECOND;
END IF;
END MakeInterval;
In your case the usage would be
SELECT MakeInterval(created_at, INTERVAL '2' HOUR)
FROM ...
But perhaps this would be an overkill in your situation, usage without the function would be:
SELECT TRUNC(created_at) + TRUNC(EXTRACT(HOUR FROM created_at) / 2) * 2 * INTERVAL '1' HOUR
FROM ...

Extracting the total number of seconds from an interval data-type

When subtracting timestamps the return value is an interval data-type. Is there an elegant way to convert this value into the total number of (milli/micro) seconds in the interval, i.e. an integer.
The following would work, but it's not very pretty:
select abs( extract( second from interval_difference )
+ extract( minute from interval_difference ) * 60
+ extract( hour from interval_difference ) * 60 * 60
+ extract( day from interval_difference ) * 60 * 60 * 24
)
from ( select systimestamp - (systimestamp - 1) as interval_difference
from dual )
Is there a more elegant method in SQL or PL/SQL?
An easy way:
select extract(day from (ts1-ts2)*86400) from dual;
The idea is to convert the interval value into days by times 86400 (= 24*60*60).
Then extract the 'day' value which is actually second value we wanted.
I hope this help:
zep#dev> select interval_difference
2 ,sysdate + (interval_difference * 86400) - sysdate as fract_sec_difference
3 from (select systimestamp - (systimestamp - 1) as interval_difference
4 from dual)
5 ;
INTERVAL_DIFFERENCE FRACT_SEC_DIFFERENCE
------------------------------------------------------------------------------- --------------------
+000000001 00:00:00.375000 86400,375
With your test:
zep#dev> select interval_difference
2 ,abs(extract(second from interval_difference) +
3 extract(minute from interval_difference) * 60 +
4 extract(hour from interval_difference) * 60 * 60 +
5 extract(day from interval_difference) * 60 * 60 * 24) as your_sec_difference
6 ,sysdate + (interval_difference * 86400) - sysdate as fract_sec_difference
7 ,round(sysdate + (interval_difference * 86400) - sysdate) as sec_difference
8 ,round((sysdate + (interval_difference * 86400) - sysdate) * 1000) as millisec_difference
9 from (select systimestamp - (systimestamp - 1) as interval_difference
10 from dual)
11 /
INTERVAL_DIFFERENCE YOUR_SEC_DIFFERENCE FRACT_SEC_DIFFERENCE SEC_DIFFERENCE MILLISEC_DIFFERENCE
------------------------------------------------------------------------------- ------------------- -------------------- -------------- -------------------
+000000001 00:00:00.515000 86400,515 86400,515 86401 86400515
zep#dev>
I've found this to work. Apparently, if you do arithmetics with timestamps they are converted to some internal datatype that, when substracted from each other, returns the interval as a number.
Easy? Yes. Elegant? No. Gets the work done? Oh yeah.
SELECT ( (A + 0) - (B + 0) ) * 24 * 60 * 60
FROM
(
SELECT SYSTIMESTAMP A,
SYSTIMESTAMP - INTERVAL '1' MINUTE B
FROM DUAL
);
Unfortunately, I don't think that there is an alternative (or more elegant) way of calculating total seconds from an interval type in pl/sql. As this article mentions:
... unlike .NET, Oracle provides no simple equivalent to TimeSpan.TotalSeconds.
therefore extracting day, hour etc from the interval and multiplying them with corresponding values seems like the only way.
Based on zep's answer, I wrapped things up into a function for your convenience:
CREATE OR REPLACE FUNCTION intervalToSeconds(
pMinuend TIMESTAMP , pSubtrahend TIMESTAMP ) RETURN NUMBER IS
vDifference INTERVAL DAY TO SECOND ;
vSeconds NUMBER ;
BEGIN
vDifference := pMinuend - pSubtrahend ;
SELECT EXTRACT( DAY FROM vDifference ) * 86400
+ EXTRACT( HOUR FROM vDifference ) * 3600
+ EXTRACT( MINUTE FROM vDifference ) * 60
+ EXTRACT( SECOND FROM vDifference )
INTO
vSeconds
FROM DUAL ;
RETURN vSeconds ;
END intervalToSeconds ;
Use following query:
select (cast(timestamp1 as date)-cast(timestamp2 as date))*24*60*60)
Similar to #Zhaoping Lu answer but directly extracting seconds instead of getting them from the number of days.
SELECT extract(second from (end_date - start_date)) as "Seconds number"
FROM my_table
(worked on PostgresSQL 9.6.1)
A shorter method to convert timestamp to nanoseconds.
SELECT (EXTRACT(DAY FROM (
SYSTIMESTAMP --Replace line with desired timestamp --Maximum value: TIMESTAMP '3871-04-29 10:39:59.999999999 UTC'
- TIMESTAMP '1970-01-01 00:00:00 UTC') * 24 * 60) * 60 + EXTRACT(SECOND FROM
SYSTIMESTAMP --Replace line with desired timestamp
)) * 1000000000 AS NANOS FROM DUAL;
NANOS
1598434427263027000
A method to convert nanoseconds to timestamp.
SELECT TIMESTAMP '1970-01-01 00:00:00 UTC' + numtodsinterval(
1598434427263027000 --Replace line with desired nanoseconds
/ 1000000000, 'SECOND') AS TIMESTAMP FROM dual;
TIMESTAMP
26/08/20 09:33:47,263027000 UTC
As expected, above methods' results are not affected by time zones.
A shorter method to convert interval to nanoseconds.
SELECT (EXTRACT(DAY FROM (
INTERVAL '+18500 09:33:47.263027' DAY(5) TO SECOND --Replace line with desired interval --Maximum value: INTERVAL '+694444 10:39:59.999999999' DAY(6) TO SECOND(9) or up to 3871 year
) * 24 * 60) * 60 + EXTRACT(SECOND FROM (
INTERVAL '+18500 09:33:47.263027' DAY(5) TO SECOND --Replace line with desired interval
))) * 1000000000 AS NANOS FROM DUAL;
NANOS
1598434427263027000
A method to convert nanoseconds to interval.
SELECT numtodsinterval(
1598434427263027000 --Replace line with desired nanoseconds
/ 1000000000, 'SECOND') AS INTERVAL FROM dual;
INTERVAL
+18500 09:33:47.263027
Replace 1000000000 by 1000, for example, if you'd like to work with milliseconds instead of nanoseconds.
I've tried some of posted methods, but a got the exception "ORA-01873: the leading precision of the interval is too smalll" when multiplying the interval by 86400, so I've decided do post the methods that works for me.
SELECT to_char(ENDTIME,'yyyymmddhh24missff')-to_char(STARTTIME,'yyyymmddhh24missff') AS DUR
FROM DUAL;
yyyymmddhh24miss- WILL GIVE DURATION IN SEC
yyyymmddhh24mi DURATION IN MIN
yyyymmddhh24 - DURATION - HOURS
yyyymmdd DURATION IN DAYS