Oracle SQL invalid number on toad - sql

I have made this query but when I execute it, I got error about "invalid number".
But in SQL Developer for Oracle, there is no error; I got the result that I want but in Toad I got 'Invalid Number' .
DECLARE v_rep number;
BEGIN
EXECUTE IMMEDIATE
'SELECT to_number(REPLACE(max(substr(to_char(r_timestamp_arr,''HH24:MI''),1,2) ||
ltrim(to_char(round(to_number(Substr(to_char(r_timestamp_arr, ''HH24:MI''),4,2)) /
60,2),''.00''))), ''.'', '','')) -
to_number(REPLACE(MIN(substr(to_char(r_timestamp_arr,''HH24:MI''),1,2) ||
ltrim(to_char(round(to_number(Substr(to_char(r_timestamp_arr, ''HH24:MI''),4,2)) /
60,2),''.00''))), ''.'', '',''))
FROM TV_MAX
WHERE TV_UID = ''7a87e8e4861a4d0aae65da1a7248b256'''
INTO v_rep;
END ;

You don't need EXECUTE IMMEDIATE and don't need to use strings:
Oracle Setup:
CREATE TABLE tv_max ( tv_uid, r_timestamp_arr ) AS
SELECT '7a87e8e4861a4d0aae65da1a7248b256', DATE '2019-12-27' + INTERVAL '00:00' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT '7a87e8e4861a4d0aae65da1a7248b256', DATE '2019-12-27' + INTERVAL '01:30' HOUR TO MINUTE FROM DUAL;
Query 1:
If you want to ignore the date component of the date & time:
DECLARE
v_rep NUMBER;
BEGIN
SELECT ( MAX( r_timestamp_arr - TRUNC( r_timestamp_arr ) )
- MIN( r_timestamp_arr - TRUNC( r_timestamp_arr ) )
) * 24
INTO v_rep
FROM tv_max
WHERE TV_UID = '7a87e8e4861a4d0aae65da1a7248b256';
DBMS_OUTPUT.PUT_LINE( v_rep );
END;
/
Query 2:
If you want the min/max respecting the date component then the query can be even simpler:
DECLARE
v_rep NUMBER;
BEGIN
SELECT ( MAX( r_timestamp_arr ) - MIN( r_timestamp_arr ) ) * 24
INTO v_rep
FROM tv_max
WHERE TV_UID = '7a87e8e4861a4d0aae65da1a7248b256';
DBMS_OUTPUT.PUT_LINE( v_rep );
END;
/
Output:
For the test data, both output:
1.5
db<>fiddle here

Looks like You want to know the difference between max and min hour (including minutes, excluding seconds), date part truncated. So take truncated times, subtract as dates, you will get result in days, multiply by 24, result will be in hours. Query does not depend on NLS settings:
select 24 * (to_date(max(to_char(r_timestamp_arr, 'hh24:mi')), 'hh24:mi')
- to_date(min(to_char(r_timestamp_arr, 'hh24:mi')), 'hh24:mi')) as diff
from tv_max
where tv_uid = '7a87e8e4861a4d0aae65da1a7248b256'
dbfiddle

Related

How to get hour and min from timestamp variable in Oracle SQL

I got a timestamp variable like this:
INSERT INTO Table VALUES(TO_TIMESTAMP('2021-02-17 17:00','YYYY-MM-DD HH24:MI'));
I've created a trigger and my aim is to get the hour and min from that attribute so that I can compare them in two cursors like time.cur1 = time.cur2 (supposing that time is hour:min or hour+min), is there any cast like for the date,
CAST((timestamp) AS DATE)
should I create a new type after extracting the hour and min with
SELECT EXTRACT(HOUR FROM timestamp) FROM Table;
SELECT EXTRACT(MIN FROM timestamp) FROM Table;
or there is another way? (I'm using Oracle Database 11g). Thanks.
New type? No, put those values into a NUMBER datatype variables.
SQL> declare
2 l_hour number;
3 l_min number;
4 begin
5 select extract (hour from systimestamp),
6 extract (minute from systimestamp)
7 into l_hour,
8 l_min
9 from dual;
10
11 dbms_output.put_line('Hour: ' || l_hour ||'; minute: ' || l_min);
12 end;
13 /
Hour: 11; minute: 47
PL/SQL procedure successfully completed.
SQL>
SELECT TO_CHAR(SYSDATE, 'HH24') AS HOUR, TO_CHAR(SYSDATE, 'MI') AS MINUTS FROM DUAL;
TO YOUR EXAMPLE:
INSERT INTO Table VALUES(HOUR, MINUTS)
SELECT TO_CHAR(SYSDATE, 'HH24') AS HOUR, TO_CHAR(SYSDATE, 'MI') AS MINUTS;
FROM <EVERY_TABLE_OR_DUAL>;

Slow query when using datediff function in Oracle

As my title, I have the following code:
SELECT
*
FROM
de.Department
WHERE
de.flag = 1
AND de.DepartmentNum IN (10,4)
AND de.status IN (0,-1,100)
AND datediff('dd',de.datequit,'30-SEP-19') > 9
The datediff function make my query run very slow(16s for 11 records), and cost also very high(~43k).
Here is my datediff function code
create or replace FUNCTION DATEDIFF
(
P_TYPE_DATE IN VARCHAR2
, P_START_DATE IN TIMESTAMP
, P_END_DATE IN TIMESTAMP
) RETURN NUMBER AS
v_Result NUMBER := -1;
BEGIN
IF P_TYPE_DATE IS NOT NULL AND P_START_DATE IS NOT NULL AND P_END_DATE IS NOT NULL THEN
CASE UPPER(P_TYPE_DATE)
WHEN 'DD' THEN RETURN ROUND(TRUNC(P_END_DATE,'DD') - TRUNC(P_START_DATE,'DD'),0);
WHEN 'HH' THEN RETURN ROUND((TRUNC(P_END_DATE,'HH') - TRUNC(P_START_DATE,'HH')) * 24,0);
WHEN 'MI' THEN RETURN ROUND((TRUNC(P_END_DATE,'MI') - TRUNC(P_START_DATE,'MI')) * 24 * 60,0);
WHEN 'SS' THEN RETURN ROUND((TRUNC(P_END_DATE,'MI') - TRUNC(P_START_DATE,'MI')) * 24 * 60 * 60 + extract(second from (P_END_DATE - P_START_DATE)),0);
ELSE RETURN NULL;
END CASE;
END IF;
RETURN NULL;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END DATEDIFF;
I used SELECT * because I want to get almost column in Department table, so it no more change if I SELECT some columns which I need.
Can I re-write to improve performance and cost?
Mayny thanks!
I created a function named datediff as a datediff function in SQL, sir
Don't use custom functions as they prevent Oracle from using an index on the column; instead just compare the column to the static values:
SELECT *
FROM Department
WHERE flag = 1
AND DepartmentNum IN (10,4)
AND status IN (0,-1,100)
AND datequit > DATE '2019-09-30' + INTERVAL '9' DAY
or
AND datequit > DATE '2019-09-30' + NUMTODSINTERVAL( 9, 'DAY' )
or
AND datequit > DATE '2019-09-30' + 9
Here is my datediff function code
...
WHEN 'DD' THEN RETURN ROUND(TRUNC(P_END_DATE,'DD') - TRUNC(P_START_DATE,'DD'),0);
...
If you want to do an equivalent comparison to using TRUNC to ignore the time components then change from using greater-than comparison to using greater-than-or-equal-to and add one time unit (day in your example) to the expected difference. For example:
SELECT *
FROM Department
WHERE flag = 1
AND DepartmentNum IN (10,4)
AND status IN (0,-1,100)
AND datequit >= DATE '2019-09-30' + INTERVAL '10' DAY

How to sum column which stores times in hh24:mi:ss in Oracle Sql?

I have a PROCESS_TIME with data type VARCHAR2(32),
in which I store the times as hh24:mi:ss,
and I intend to add these times on some grouping logic.
A minified version of the table
CREATE TABLE "SCHEMA"."MY_TABLE"
( "MY_TABLE_ID" VARCHAR2(32 BYTE) NOT NULL ENABLE,
"START_TIME" DATE NOT NULL ENABLE,
"END_TIME" DATE NOT NULL ENABLE,
"LOAD_PROCESS_TIME" VARCHAR2(32 BYTE) DEFAULT '00:00:00',
)
and a minified version of Insert
Insert into MY_TABLE (MY_TABLE_ID,START_TIME,END_TIME,LOAD_PROCESS_TIME)
values ('8880508C9AC4441DB8E16E023F206C2F',to_date('05/11/2018 07:22','MM/DD/YYYY HH:MI'),to_date('05/11/2018 08:22','MM/DD/YYYY HH:MI'),'01:00:14');
Insert into MY_TABLE (MY_TABLE_ID,START_TIME,END_TIME,LOAD_PROCESS_TIME) values ('C858EB646A794D04B5C77779C50EBFCF',
to_date('05/12/2018 10:20','MM/DD/YYYY HH:MI'),
to_date('05/12/2018 11:20','MM/DD/YYYY HH:MI'),
'02:30:10');
Intended Query
SELECT TO_CHAR(TRUNC(END_TIME, 'DD'), 'DD-MON-YY'),
sum(LOAD_PROCESS_TIME)
FROM MY_TABLE
WHERE END_TIME > SYSDATE -14
GROUP BY TRUNC(END_TIME,'DD')
ORDER BY TRUNC(END_TIME,'DD');
Can you please help me achieve this using Oracle SQL?
You can calculate the time interval as a fractional number of days and sum that:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE table_name ( PROCESS_TIME ) AS
SELECT '01:23:04' FROM DUAL UNION ALL
SELECT '23:00:00' FROM DUAL UNION ALL
SELECT '11:36:56' FROM DUAL;
Query 1:
SELECT SUM(
TO_DATE( PROCESS_TIME, 'HH24:MI:SS' )
- TO_DATE( '00:00:00', 'HH24:MI:SS' )
) AS num_days
FROM table_name
Results:
| NUM_DAYS |
|----------|
| 1.5 |
You could also create a custom object to aggregate INTERVAL DAY TO SECOND data types:
CREATE TYPE IntervalSumType AS OBJECT(
total INTERVAL DAY(9) TO SECOND(9),
STATIC FUNCTION ODCIAggregateInitialize(
ctx IN OUT IntervalSumType
) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateIterate(
self IN OUT IntervalSumType,
value IN INTERVAL DAY TO SECOND
) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateTerminate(
self IN OUT IntervalSumType,
returnValue OUT INTERVAL DAY TO SECOND,
flags IN NUMBER
) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateMerge(
self IN OUT IntervalSumType,
ctx IN OUT IntervalSumType
) RETURN NUMBER
);
/
CREATE OR REPLACE TYPE BODY IntervalSumType
IS
STATIC FUNCTION ODCIAggregateInitialize(
ctx IN OUT IntervalSumType
) RETURN NUMBER
IS
BEGIN
ctx := IntervalSumType( INTERVAL '0' DAY );
RETURN ODCIConst.SUCCESS;
END;
MEMBER FUNCTION ODCIAggregateIterate(
self IN OUT IntervalSumType,
value IN INTERVAL DAY TO SECOND
) RETURN NUMBER
IS
BEGIN
IF value IS NOT NULL THEN
self.total := self.total + value;
END IF;
RETURN ODCIConst.SUCCESS;
END;
MEMBER FUNCTION ODCIAggregateTerminate(
self IN OUT IntervalSumType,
returnValue OUT INTERVAL DAY TO SECOND,
flags IN NUMBER
) RETURN NUMBER
IS
BEGIN
returnValue := self.total;
RETURN ODCIConst.SUCCESS;
END;
MEMBER FUNCTION ODCIAggregateMerge(
self IN OUT IntervalSumType,
ctx IN OUT IntervalSumType
) RETURN NUMBER
IS
BEGIN
self.total := self.total + ctx.total;
RETURN ODCIConst.SUCCESS;
END;
END;
/
And then a custom aggregation function:
CREATE FUNCTION SUM_INTERVALS( value INTERVAL DAY TO SECOND )
RETURN INTERVAL DAY TO SECOND
PARALLEL_ENABLE AGGREGATE USING IntervalSumType;
/
Query 2:
SELECT SUM_INTERVALS( TO_DSINTERVAL( '+0 '||PROCESS_TIME ) )
AS total_difference
FROM table_name
Results:
| TOTAL_DIFFERENCE |
|------------------|
| 1 12:0:0.0 |
Update - Query 3:
SELECT TO_CHAR( num_days * 24, 'FM99990' )
|| ':' || TO_CHAR( MOD( num_days * 24*60, 60 ), 'FM00' )
|| ':' || TO_CHAR( MOD( num_days * 24*60*60, 60 ), 'FM00' )
AS total_time
FROM (
SELECT SUM(
TO_DATE( PROCESS_TIME, 'HH24:MI:SS' )
- TO_DATE( '00:00:00', 'HH24:MI:SS' )
) AS num_days
FROM table_name
)
Results:
| TOTAL_TIME |
|------------|
| 36:00:00 |
------------------------------answer----------------------------------------
As a completion to the discussion , the query which worked was
SELECT TO_CHAR(TRUNC(END_TIME, 'DD'), 'DD-MON-YY'),
to_char(sum(TO_DATE(LOAD_PROCESS_TIME,'HH24:MI:SS')- TO_DATE( '00:00:00', 'HH24:MI:SS' ))*24,'FM00')
|| ':'|| TO_CHAR(MOD(sum(TO_DATE(LOAD_PROCESS_TIME,'HH24:MI:SS')- TO_DATE( '00:00:00', 'HH24:MI:SS' ))*24*60,60),'FM00')
||':'|| TO_CHAR(MOD(sum(TO_DATE(LOAD_PROCESS_TIME,'HH24:MI:SS')- TO_DATE( '00:00:00', 'HH24:MI:SS' ))*24*60*60,60),'FM00')
as Days
FROM MY_TABLE
WHERE END_TIME > SYSDATE -30
GROUP BY TRUNC(END_TIME,'DD')
ORDER BY TRUNC(END_TIME,'DD');

Oracle PL SQL - Issue with EXECUTE IMMEDIATE

DECLARE
start_date VARCHAR2(12);
end_date VARCHAR2(12);
start_epochtime VARCHAR2(15);
end_epochtime VARCHAR2(15);
v_sql VARCHAR2(1024);
BEGIN
SELECT to_char(current_date,'YYYY-MM-DD') into start_date from dual;
SELECT to_char(current_date - 30,'YYYY-MM-DD') into end_date from dual;
dbms_output.put_line(start_date);
dbms_output.put_line(end_date);
/* Below section will convert date to epochtime with hard code date value */
SELECT CAST((TO_DATE('2016-01-01','YYYY-MM-DD') - TO_DATE('1970-01- 01','YYYY-MM-DD') ) * 24 * 60 * 60 * 1000 AS VARCHAR(15)) into start_epochtime FROM DUAL;
SELECT CAST((TO_DATE('2016-01-01','YYYY-MM-DD') - TO_DATE('1970-01-01','YYYY-MM-DD') - 30) * 24 * 60 * 60 * 1000 AS VARCHAR(15)) into end_epochtime FROM DUAL;
dbms_output.put_line(start_epochtime);
dbms_output.put_line(end_epochtime);
/* Below section will convert date to epochtime with a variable */
SELECT CAST((TO_DATE(start_date,'YYYY-MM-DD') - TO_DATE('1970-01-01','YYYY-MM-DD') ) * 24 * 60 * 60 * 1000 AS VARCHAR(15)) into start_epochtime FROM DUAL;
SELECT CAST((TO_DATE(end_date,'YYYY-MM-DD') - TO_DATE('1970-01-01','YYYY-MM-DD') - 30) * 24 * 60 * 60 * 1000 AS VARCHAR(15)) into end_epochtime FROM DUAL;
dbms_output.put_line(start_epochtime);
dbms_output.put_line(end_epochtime);
EXECUTE IMMEDIATE q'[select to_char((TO_DATE('1970-01-01','yyyy-mm-dd') + (m.CREATIONDATE/1000/24/60/60)),'YYYY-MM-DD'),count(1) from jivemessage_us m where m.CREATIONDATE >= :start_epochtime and m.CREATIONDATE <= :end_epochtime group by to_char((TO_DATE('1970-01-01','yyyy-mm-dd') + (m.CREATIONDATE/1000/24/60/60)),'YYYY-MM-DD') order by 1]';
END;
/
I got this error ORA-01008: not all variables bound when i am running this pl sql. And, All statements are running fine except EXECUTE IMMEDIATE q'';
There doesn't appear to be a reason to use EXECUTE IMMEDIATE here. You're not building a dynamic query, nor are you executing a DDL statement. I suggest replacing the EXECUTE IMMEDIATE with
select to_char((TO_DATE('1970-01-01','yyyy-mm-dd') +
(m.CREATIONDATE/1000/24/60/60)),'YYYY-MM-DD'),
count(1)
from jivemessage_us m
where m.CREATIONDATE >= start_epochtime and
m.CREATIONDATE <= end_epochtime
group by to_char((TO_DATE('1970-01-01','yyyy-mm-dd') +
(m.CREATIONDATE/1000/24/60/60)),'YYYY-MM-DD')
order by 1
Best of luck.
If you really want to do it all in PL/SQL then you can do:
VARIABLE cur REFCURSOR;
DECLARE
start_date VARCHAR2(12);
end_date VARCHAR2(12);
start_epochtime VARCHAR2(15);
end_epochtime VARCHAR2(15);
v_sql VARCHAR2(1024);
BEGIN
start_date := TO_CHAR(current_date, 'YYYY-MM-DD');
end_date := TO_CHAR(current_date - 30, 'YYYY-MM-DD');
dbms_output.put_line(start_date);
dbms_output.put_line(end_date);
/* Below section will convert date to epochtime with hard code date value */
start_epochtime := ( DATE '2016-01-01' - DATE '1970-01-01' ) * 24 * 60 * 60 * 1000;
end_epochtime := ( DATE '2016-01-01' - DATE '1970-01-01' - 30 ) * 24 * 60 * 60 * 1000;
dbms_output.put_line(start_epochtime);
dbms_output.put_line(end_epochtime);
/* Below section will convert date to epochtime with a variable */
start_epochtime := ( CURRENT_DATE - DATE '1970-01-01' ) * 24 * 60 * 60 * 1000;
end_epochtime := ( CURRENT_DATE - 30 - DATE '1970-01-01' ) * 24 * 60 * 60 * 1000;
dbms_output.put_line(start_epochtime);
dbms_output.put_line(end_epochtime);
OPEN :cur FOR
select to_char(DATE '1970-01-01' + CREATIONDATE/1000/24/60/60,'YYYY-MM-DD'),
count(1)
from jivemessage_us
where CREATIONDATE BETWEEN start_epochtime and end_epochtime
group by CREATIONDATE
order by 1;
END;
/
PRINT cur;
But it would be simpler to do it in SQL:
select to_char(DATE '1970-01-01' + CREATIONDATE/1000/24/60/60,'YYYY-MM-DD'),
count(1)
from jivemessage_us
where CREATIONDATE BETWEEN ( CURRENT_DATE - DATE '1970-01-01' )*24*60*60*1000
AND ( CURRENT_DATE - 30 - DATE '1970-01-01' )*24*60*60*1000
group by CREATIONDATE
order by 1;
(Note: I've left your logic as-is but moved it from continually context switching from PL/SQL to SQL to just use PL/SQL as much as possible and ANSI Date literals; however, I do think that you have the -30 in the wrong places as it ought to be for the start_epochtime and not the end_epochtime.)

Oracle Convert Seconds to Hours:Minutes:Seconds

I have a requirement to display user available time in Hours:Minutes:Seconds format from a given total number of seconds value. Appreciate if you know a ORACLE function to do the same. I'm using Oracle.
Thank you for your time.
If you're just looking to convert a given number of seconds into HH:MI:SS format, this should do it
SELECT
TO_CHAR(TRUNC(x/3600),'FM9900') || ':' ||
TO_CHAR(TRUNC(MOD(x,3600)/60),'FM00') || ':' ||
TO_CHAR(MOD(x,60),'FM00')
FROM DUAL
where x is the number of seconds.
Try this one.
Very simple and easy to use
select to_char(to_date(10000,'sssss'),'hh24:mi:ss') from dual;
The following code is less complex and gives the same result. Note that 'X' is the number of seconds to be converted to hours.
In Oracle use:
SELECT TO_CHAR (TRUNC (SYSDATE) + NUMTODSINTERVAL (X, 'second'),
'hh24:mi:ss'
) hr
FROM DUAL;
In SqlServer use:
SELECT CONVERT(varchar, DATEADD(s, X, 0), 108);
If you have a variable containing f.e. 1 minute(in seconds), you can add it to the systimestamp then use to_char to select the different time parts from it.
select to_char(systimestamp+60/(24*60*60), 'yyyy.mm.dd HH24:mi:ss') from dual
For the comment on the answer by vogash, I understand that you want something like a time counter, thats because you can have more than 24 hours. For this you can do the following:
select to_char(trunc(xxx/3600)) || to_char(to_date(mod(xxx, 86400),'sssss'),':mi:ss') as time
from dual;
xxx are your number of seconds.
The first part accumulate the hours and the second part calculates the remaining minutes and seconds. For example, having 150023 seconds it will give you 41:40:23.
But if you always want have hh24:mi:ss even if you have more than 86000 seconds (1 day) you can do:
select to_char(to_date(mod(xxx, 86400),'sssss'),'hh24:mi:ss') as time
from dual;
xxx are your number of seconds.
For example, having 86402 seconds it will reset the time to 00:00:02.
Unfortunately not... However, there's a simple trick if it's going to be less than 24 hours.
Oracle assumes that a number added to a date is in days. Convert the number of seconds into days. Add the current day, then use the to_date function to take only the parts your interested in. Assuming you have x seconds:
select to_char(sysdate + (x / ( 60 * 60 * 24 ) ), 'HH24:MI:SS')
from dual
This won't work if there's more than 24 hours, though you can remove the current data again and get the difference in days, hours, minutes and seconds.
If you want something like: 51:10:05, i.e. 51 hours, 10 minutes and 5 seconds then you're going to have to use trunc.
Once again assuming that you have x seconds...
The number of hours is trunc(x / 60 / 60)
The number of minutes is trunc((x - ( trunc(x / 60 / 60) * 60 * 60 )) / 60)
The number of seconds is therefore the x - hours * 60 * 60 - minutes * 60
Leaving you with:
with hrs as (
select x, trunc(x / 60 / 60) as h
from dual
)
, mins as (
select x, h, trunc((x - h * 60 * 60) / 60) as m
from hrs
)
select h, m, x - (h * 60 * 60) - (m * 60)
from mins
I've set up a SQL Fiddle to demonstrate.
The following is Yet Another Way (tm) - still involves a little calculation but provides an example of using EXTRACT to pull the individual fields out of an INTERVAL:
DECLARE
SUBTYPE BIG_INTERVAL IS INTERVAL DAY(9) TO SECOND;
i BIG_INTERVAL;
nSeconds NUMBER := 86400000;
FUNCTION INTERVAL_TO_HMS_STRING(inv IN BIG_INTERVAL)
RETURN VARCHAR2
IS
nHours NUMBER;
nMinutes NUMBER;
nSeconds NUMBER;
strHour_format VARCHAR2(10) := '09';
workInv INTERVAL DAY(9) TO SECOND(9);
BEGIN
nHours := EXTRACT(HOUR FROM inv) + (EXTRACT(DAY FROM inv) * 24);
strHour_format := TRIM(RPAD(' ', LENGTH(TRIM(TO_CHAR(ABS(nHours)))), '0') || '9');
nMinutes := ABS(EXTRACT(MINUTE FROM inv));
nSeconds := ABS(EXTRACT(SECOND FROM inv));
RETURN TRIM(TO_CHAR(nHours, strHour_format)) || ':' ||
TRIM(TO_CHAR(nMInutes, '09')) || ':' ||
TRIM(TO_CHAR(nSeconds, '09'));
END INTERVAL_TO_HMS_STRING;
BEGIN
i := NUMTODSINTERVAL(nSeconds, 'SECOND');
DBMS_OUTPUT.PUT_LINE('i (fields) = ' || INTERVAL_TO_HMS_STRING(i));
END;
The code which extracts the fields, etc, still has to contain a calculation to convert the DAY field to equivalent hours, and is not the prettiest, but wrapped up neatly in a procedure it's not too bad to use.
Share and enjoy.
Assuming your time is called st.etime below and stored in seconds, here is what I use. This handles times where the seconds are greater than 86399 seconds (which is 11:59:59 pm)
case when st.etime > 86399 then to_char(to_date(st.etime - 86400,'sssss'),'HH24:MI:SS') else to_char(to_date(st.etime,'sssss'),'HH24:MI:SS') end readable_time
My version. Show Oracle DB uptime in format DDd HHh MMm SSs
select to_char(trunc((((86400*x)/60)/60)/24)) || 'd ' ||
to_char(trunc(((86400*x)/60)/60)-24*(trunc((((86400*x)/60)/60)/24)), 'FM00') || 'h ' ||
to_char(trunc((86400*x)/60)-60*(trunc(((86400*x)/60)/60)), 'FM00') || 'm ' ||
to_char(trunc(86400*x)-60*(trunc((86400*x)/60)), 'FM00') || 's' "UPTIME"
from (select (sysdate - t.startup_time) x from V$INSTANCE t);
idea from Date / Time Arithmetic with Oracle 9/10
Convert minutes to hour:min:sec format
SELECT
TO_CHAR(TRUNC((MINUTES * 60) / 3600), 'FM9900') || ':' ||
TO_CHAR(TRUNC(MOD((MINUTES * 60), 3600) / 60), 'FM00') || ':' ||
TO_CHAR(MOD((MINUTES * 60), 60), 'FM00') AS MIN_TO_HOUR FROM DUAL
For greater than 24 hours you can include days with the following query. The returned format is days:hh24:mi:ss
Query:
select trunc(trunc(sysdate) + numtodsinterval(9999999, 'second')) - trunc(sysdate) || ':' || to_char(trunc(sysdate) + numtodsinterval(9999999, 'second'), 'hh24:mi:ss') from dual;
Output:
115:17:46:39
create or replace procedure mili(num in number)
as
yr number;
yrsms number;
mon number;
monsms number;
wk number;
wksms number;
dy number;
dysms number;
hr number;
hrsms number;
mn number;
mnsms number;
sec number;
begin
yr := FLOOR(num/31556952000);
yrsms := mod(num, 31556952000);
mon := FLOOR(yrsms/2629746000);
monsms := mod(num,2629746000);
wk := FLOOR(monsms/(604800000));
wksms := mod(num,604800000);
dy := floor(wksms/ (24*60*60*1000));
dysms :=mod(num,24*60*60*1000);
hr := floor((dysms)/(60*60*1000));
hrsms := mod(num,60*60*1000);
mn := floor((hrsms)/(60*1000));
mnsms := mod(num,60*1000);
sec := floor((mnsms)/(1000));
dbms_output.put_line(' Year:'||yr||' Month:'||mon||' Week:'||wk||' Day:'||dy||' Hour:'||hr||' Min:'||mn||' Sec: '||sec);
end;
/
begin
mili(12345678904234);
end;
create or replace function `seconds_hh_mi_ss` (seconds in number)
return varchar2
is
hours_var number;
minutes_var number;
seconds_var number;
remeinder_var number;
output_var varchar2(32);
begin
select seconds - mod(seconds,3600) into hours_var from dual;
select seconds - hours_var into remeinder_var from dual;
select (remeinder_var - mod(remeinder_var,60)) into minutes_var from dual;
select seconds - (hours_var+minutes_var) into seconds_var from dual;
output_var := hours_var/3600||':'||minutes_var/60||':'||seconds_var;
return(output_var);
end;
/
You should check out this site. The TO_TIMESTAMP section could be useful for you!
Syntax:
TO_TIMESTAMP ( string , [ format_mask ] [ 'nlsparam' ] )