Averaging a list of TIMESTAMP(6) WITH TIME ZONE times - sql

I've got 2 columns in a database of type TIMESTAMP(6) WITH TIME ZONE. I've subtracted one from the other to get the time between the two timestamps.
select lastprocesseddate-importeddate
from feedqueueitems
where eventid = 2213283
order by written desc;
How can I get an average of the list of time differences I have?
Here are a small sample of time differences:
+00 00:00:00.488871
+00 00:00:00.464286
+00 00:00:00.477107
+00 00:00:00.507042
+00 00:00:00.369144
+00 00:00:00.488918
+00 00:00:00.354797
+00 00:00:00.378801
+00 00:00:00.320040
+00 00:00:00.361242
+00 00:00:00.302327
+00 00:00:00.331441
+00 00:00:00.324065
EDIT: I also should have noted - I've tried the AVG function, and it just returns
ORA-00932: inconsistent datatypes: expected NUMBER got INTERVAL DAY TO SECOND
00932. 00000 - "inconsistent datatypes: expected %s got %s"
*Cause:
*Action:
Error at Line: 3 Column: 29
EDIT2: Just to clarify the above snippet. Line 3 is my SQL query all on one line in the following format:
select AVG(lastprocesseddate-importeddate) from feedqueueitems where eventid = 2213283;
EDIT3: Massive thanks to Matt and Alex Poole. You've both helped massively and I appreciate you taking the time to help with this and to both consistently return with updated help in response to the feedback/further problems! Thanks guys!

Use the AVG function
SELECT avg(cast(lastprocesseddate as date)-cast(importeddate as date))
FROM feedqueueitems
WHERE eventid = 2213283
ORDER BY written DESC;
On the Database with the +1 timezone for importeddate and lastprocesseddate is UTC
SELECT avg(cast(cast(lastprocesseddate as timestamp with time zone) at time zone '+01:00' as date)-cast(importeddate as date))
FROM feedqueueitems
WHERE eventid = 2213283
ORDER BY written DESC;

You could extract the time components from each gap value, which is an interval data type, so you end up with a figure in seconds (including the fractional part), and then average those:
select avg(extract(second from gap)
+ extract(minute from gap) * 60
+ extract(hour from gap) * 60 * 60
+ extract(day from gap) * 60 * 60 * 24) as avg_gap
from (
select lastprocesseddate-importeddate as gap
from feedqueueitems
where eventid = 2213283
);
A demo using a CTE to provide the interval values you showed:
with cte as (
select interval '+00 00:00:00.488871' day to second as gap from dual
union all select interval '+00 00:00:00.464286' day to second from dual
union all select interval '+00 00:00:00.477107' day to second from dual
union all select interval '+00 00:00:00.507042' day to second from dual
union all select interval '+00 00:00:00.369144' day to second from dual
union all select interval '+00 00:00:00.488918' day to second from dual
union all select interval '+00 00:00:00.354797' day to second from dual
union all select interval '+00 00:00:00.378801' day to second from dual
union all select interval '+00 00:00:00.320040' day to second from dual
union all select interval '+00 00:00:00.361242' day to second from dual
union all select interval '+00 00:00:00.302327' day to second from dual
union all select interval '+00 00:00:00.331441' day to second from dual
union all select interval '+00 00:00:00.324065' day to second from dual
)
select avg(extract(second from gap)
+ extract(minute from gap) * 60
+ extract(hour from gap) * 60 * 60
+ extract(day from gap) * 60 * 60 * 24) as avg_gap
from cte;
AVG_GAP
----------
.397544692
Or if you wanted it as an interval:
select numtodsinterval(avg(extract(second from gap)
+ extract(minute from gap) * 60
+ extract(hour from gap) * 60 * 60
+ extract(day from gap) * 60 * 60 * 24), 'SECOND') as avg_gap
...
which gives
AVG_GAP
--------------------
0 0:0:0.397544692
SQL Fiddle with answer in seconds. (It doesn't seem to like displaying intervals at the moment, so can't demo that).

This query should solve the issue.
WITH t AS
(SELECT
TIMESTAMP '2015-04-23 12:00:00.5 +02:00' AS lastprocesseddate,
TIMESTAMP '2015-04-23 12:05:10.21 UTC' AS importeddate
FROM dual)
SELECT
AVG(
EXTRACT(SECOND FROM SYS_EXTRACT_UTC(lastprocesseddate) - SYS_EXTRACT_UTC(importeddate))
+ EXTRACT(MINUTE FROM SYS_EXTRACT_UTC(lastprocesseddate) - SYS_EXTRACT_UTC(importeddate)) * 60
+ EXTRACT(HOUR FROM SYS_EXTRACT_UTC(lastprocesseddate) - SYS_EXTRACT_UTC(importeddate)) * 60 * 60
+ EXTRACT(DAY FROM SYS_EXTRACT_UTC(lastprocesseddate) - SYS_EXTRACT_UTC(importeddate)) * 60 * 60 * 24
) AS average_gap
FROM t;

Related

Convert Timestamp to minutes in Oracle after a subtraction

I'm trying to get the minute value from a Timestamp after a subtraction
First I made a subtraction:
Current Time - Target Time(INSP_FIN_DT)
(
TO_TIMESTAMP(TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD HH24:MI:SS') -
TO_TIMESTAMP(INSP_FIN_DT,'YYYY-MM-DD HH24:MI:SS')
) AS REST_TIME
the output:
+00 00:09:44.000000
What I need:
09
I already tried
SELECT SUBSTR(REST_TIME, 7,2)
But the return is ever 00, even If I convert it to Char like:
SELECT SUBSTR(TO_CHAR(REST_TIME),7,2)
How can I solve it by query?
Information here https://dba.stackexchange.com/questions/53924/how-do-i-get-the-difference-in-minutes-from-2-timestamp-columns
select
round(
(SYSDATE - cast(<other_timestamp> as date))
* 24 * 60
) as diff_minutes
from <some_table>;
For my current implementation, I'll never have more than a hour, in this case I used the bellow solution:
SYSTIMESTAMP - TO_TIMESTAMP(INSP_FIN_DT,'YYYY-MM-DD HH24:MI:SS') AS REST_TIME
Select..
EXTRACT(MINUTE FROM REST_TIME) AS REST_MINUTES
In case of more than 60 minutes, I should use:
(EXTRACT(HOUR FROM REST_TIME) * 60)
+ EXTRACT(MINUTE FROM REST_TIME) AS REST_MINUTES

Oracle SQL round up time interval to next day

How to round up time interval to next day in Oracle SQL?
select apppackage
, numtodsinterval(
sum( trunc(extract (day from (periods)) * 86400
+ extract (hour from (periods)) *3600
+ extract (minute from (periods))*60
+ extract (second from (periods)))
), 'SECOND') as retention_period
, count(apppackage) as users
from retentions
where apppackage = 'com.Freesoul.Rotter'
group by apppackage;
The output of this is
'com.Freesoul.Rotter' '+2969 04:32:47.000000' '3'
and desired output is
'com.Freesoul.Rotter' '2970' '3'
but if the output of query is
'com.Freesoul.Rotter' '+2969 00:00:00.000000' '3'
then desired output is
'com.Freesoul.Rotter' '2969' '3'
column period is of INTERVAL DAY(9) TO SECOND(6) type
and i won't mind if the retention_period is changed to number datatype.
I'll be grateful if anyone can suggest change in my query to attain the desired output.
The result of your sum is in seconds, so you don't really need to convert it to an interval at all. Just divide by 60*60*24 to get the answer in days, and round it up with ceil():
select apppackage
, ceil(sum( trunc(extract (day from (periods)) * 86400
+ extract (hour from (periods)) *3600
+ extract (minute from (periods))*60
+ extract (second from (periods)))
) / 86400) as retention_period
, count(apppackage) as users
from retentions
where apppackage = 'com.Freesoul.Rotter'
group by apppackage;
Demo with artificial data in a CTE just to mimic your expected results, for both scenarios:
-- CTE for sample data
with retentions (apppackage, periods) as (
select 'com.Freesoul.Rotter', interval '+2967 04:32:47.000000' day(9) to second(6) from dual
union all
select 'com.Freesoul.Rotter', interval '1' day from dual
union all
select 'com.Freesoul.Rotter', interval '1' day from dual
union all
select 'com.Freesoul.XYZ', interval '+2967 00:00:00.000000' day(9) to second(6) from dual
union all
select 'com.Freesoul.XYZ', interval '1' day from dual
union all
select 'com.Freesoul.XYZ', interval '1' day from dual
)
-- actual query
select apppackage
, ceil(sum( trunc(extract (day from (periods)) * 86400
+ extract (hour from (periods)) *3600
+ extract (minute from (periods))*60
+ extract (second from (periods)))
) / 86400) as retention_period
, count(apppackage) as users
from retentions
where apppackage = 'com.Freesoul.Rotter'
-- extra clause for dummy data
or apppackage = 'com.Freesoul.XYZ'
group by apppackage;
APPPACKAGE RETENTION_PERIOD USERS
------------------- ---------------- ----------
com.Freesoul.XYZ 2969 3
com.Freesoul.Rotter 2970 3
Your expected output shows a plain number. If you actually want it as an interval, but as the whole number of days, just pass ceil'd number into numtodsinterval or more simply (and usually faster for some reason) multiply by interval '1' day.
With the same dummy data:
select apppackage
, ceil(sum( trunc(extract (day from (periods)) * 86400
+ extract (hour from (periods)) *3600
+ extract (minute from (periods))*60
+ extract (second from (periods)))
) / 86400) * interval '1' day as retention_period
, count(apppackage) as users
...
APPPACKAGE RETENTION_PERIOD USERS
------------------- --------------------- ----------
com.Freesoul.XYZ +2969 00:00:00.000000 3
com.Freesoul.Rotter +2970 00:00:00.000000 3
As #mathguy pointed out, you probably don't need or want the trunc() call in there; that is removing the fractional seconds from each period before they are summed, which sounds insignificant but could easily affect the result you get.
How about this?
CASE WHEN numtodsinterval(extract (day from periods), 'DAY') = periods THEN
extract (day from periods)
ELSE
extract (day from periods) + 1
END

How to convert milliseconds to Time(hh:mm:ss) in Oracle

I would like to convert in PL/SQL miliseconds to Time(hh:mm:ss)
21649000 to 06:00:49
or
83293000 to 23:08:13
Use NUMTODSINTERVAL with SECOND option :
select NUMTODSINTERVAL( 83293000 / 1000, 'SECOND' ) "Time" from dual t;
Time
-------------------
+000000000 23:08:13
This is a quite self-explanatory way:
select val,
floor( val / 1000 / 60 / 60 ) as hours,
floor( mod(val / 1000 / 60 , 60) ) as minutes,
floor( mod(val / 1000 , 60) ) as seconds
from (
select 21649000 val from dual union
select 83293000 val from dual
)
VAL HOURS MINUTES SECONDS
---------- ---------- ---------- ----------
21649000 6 0 49
83293000 23 8 13
This does not handle days, so the number of milliseconds must be less than 24 hours.
This gives numbers, you can edit it the way you need to get your desired output format/type.
If you only want second precision you could divide the number by 1000 to get seconds, and by 86400 to get a fraction of a day, then add that to midnight on any nominal date - and convert the result to a string:
select to_char(date '1970-01-01' + (21649000/86400000), 'HH24:MI:SS') as time
from dual;
TIME
--------
06:00:49
select to_char(date '1970-01-01' + (83293000/86400000), 'HH24:MI:SS') as time
from dual;
TIME
--------
23:08:13
This only works properly for values less than a day, i.e. where your original number is less than 86400000; higher than that and you only see the leftover in the second day.
The below query worked for me to convert to the Milliseconds to the HH:MM:SS
SELECT
TO_CHAR(TRUNC([ColumnName]/3600000),'FM9900') || ':' ||
TO_CHAR(TRUNC(MOD([ColumnName],3600000)/60000),'FM00') || ':' ||
TO_CHAR( trunc(MOD([ColumnName],60000)/1000),'FM00') FROM [TableName]`

Oracle Add 1 hour in SQL

I am just trying to add 1 hour to a value, it is kind of complicated on where and why i am doing this but basically i just need to query something like this
select DATE_ADD(hh,1,'2014-10-15 03:30:00 pm') from dual
I keep reading old articles that say to use dateAdd or date_add but I keep getting invalid identifier errors.
select sysdate + 1/24 from dual;
sysdate is a function without arguments which returns DATE type
+ 1/24 adds 1 hour to a date
select to_char(to_date('2014-10-15 03:30:00 pm', 'YYYY-MM-DD HH:MI:SS pm') + 1/24, 'YYYY-MM-DD HH:MI:SS pm') from dual;
Use an interval:
select some_date_column + interval '1' hour
from your_table;
You can use INTERVAL type or just add calculated number value - "1" is equal "1 day".
first way:
select date_column + INTERVAL '0 01:00:00' DAY TO SECOND from dual;
second way:
select date_column + 1/24 from dual;
First way is more convenient when you need to add a complicated value - for example, "1 day 3 hours 25 minutes 49 seconds".
See also: http://www.oracle-base.com/articles/misc/oracle-dates-timestamps-and-intervals.php
Also you have to remember that oracle have two interval types - DAY TO SECOND and YEAR TO MONTH.
As for me, one interval type would be better, but I hope people in oracle knows, what they do ;)
Old way:
SELECT DATE_COLUMN + 1 is adding a day
SELECT DATE_COLUMN + N /24 to add hour(s) - N being number of hours
SELECT DATE_COLUMN + N /1440 to add minute(s) - N being number of minutes
SELECT DATE_COLUMN + N /86400 to add second(s) - N being number of seconds
Using INTERVAL:
SELECT DATE_COLUMN + INTERVAL 'N' HOUR or MINUTE or SECOND - N being a number of hours or minutes or seconds.
To add/subtract from a DATE, you have 2 options :
Method #1 :
The easiest way is to use + and - to add/subtract days, hours, minutes, seconds, etc.. from a DATE, and ADD_MONTHS() function to add/subtract months and years from a DATE. Why ? That's because from days, you can get hours and any smaller unit (1 hour = 1/24 days), (1 minute = 1/1440 days), etc... But you cannot get months and years, as that depends on the month and year themselves, hence ADD_MONTHS() and no add_years(), because from months, you can get years (1 year = 12 months).
Let's try them :
SELECT TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS') FROM dual; -- prints current date: 19-OCT-2019 20:42:02
SELECT TO_CHAR((SYSDATE + 1/24), 'DD-MON-YYYY HH24:MI:SS') FROM dual; -- prints date + 1 hour: 19-OCT-2019 21:42:02
SELECT TO_CHAR((SYSDATE + 1/1440), 'DD-MON-YYYY HH24:MI:SS') FROM dual; -- prints date + 1 minute: 19-OCT-2019 20:43:02
SELECT TO_CHAR((SYSDATE + 1/86400), 'DD-MON-YYYY HH24:MI:SS') FROM dual; -- prints date + 1 second: 19-OCT-2019 20:42:03
-- Same goes for subtraction.
SELECT SYSDATE FROM dual; -- prints current date: 19-OCT-19
SELECT ADD_MONTHS(SYSDATE, 1) FROM dual; -- prints date + 1 month: 19-NOV-19
SELECT ADD_MONTHS(SYSDATE, 12) FROM dual; -- prints date + 1 year: 19-OCT-20
SELECT ADD_MONTHS(SYSDATE, -3) FROM dual; -- prints date - 3 months: 19-JUL-19
Method #2 : Using INTERVALs, you can or subtract an interval (duration) from a date easily. More than that, you can combine to add or subtract multiple units at once (e.g 5 hours and 6 minutes, etc..)
Examples :
SELECT TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS') FROM dual; -- prints current date: 19-OCT-2019 21:34:15
SELECT TO_CHAR((SYSDATE + INTERVAL '1' HOUR), 'DD-MON-YYYY HH24:MI:SS') FROM dual; -- prints date + 1 hour: 19-OCT-2019 22:34:15
SELECT TO_CHAR((SYSDATE + INTERVAL '1' MINUTE), 'DD-MON-YYYY HH24:MI:SS') FROM dual; -- prints date + 1 minute: 19-OCT-2019 21:35:15
SELECT TO_CHAR((SYSDATE + INTERVAL '1' SECOND), 'DD-MON-YYYY HH24:MI:SS') FROM dual; -- prints date + 1 second: 19-OCT-2019 21:34:16
SELECT TO_CHAR((SYSDATE + INTERVAL '01:05:00' HOUR TO SECOND), 'DD-MON-YYYY HH24:MI:SS') FROM dual; -- prints date + 1 hour and 5 minutes: 19-OCT-2019 22:39:15
SELECT TO_CHAR((SYSDATE + INTERVAL '3 01' DAY TO HOUR), 'DD-MON-YYYY HH24:MI:SS') FROM dual; -- prints date + 3 days and 1 hour: 22-OCT-2019 22:34:15
SELECT TO_CHAR((SYSDATE - INTERVAL '10-3' YEAR TO MONTH), 'DD-MON-YYYY HH24:MI:SS') FROM dual; -- prints date - 10 years and 3 months: 19-JUL-2009 21:34:15
The calculation is simple
if you want to add 1 hour in the date .
every day have 24 hour , you can add .
select sysdate + 1/24 from dual;
if you want 1 day to add
select sysdate + 24/24 from dual;
or
select sysdate + 1 from dual;
same as for 2, 3 , 4 day
For static date you have the answer below.

Select Dates where time is less or equal to '12:00' Oracle

I require a query that selects rows where the time is less or equal to 12:00
I had something like this in mind:
SELECT daterow FROM datecolumn WHERE daterow <= TO_DATE('12:00, HH24:MI')
However i get an error:
ORA-01843: not a valid month
How would i go about to get all rows that have a time less than 12:00 mid-day?
Try this,
SELECT daterow FROM datecolumn WHERE daterow <= TO_DATE('12:00', 'HH24:MI');
Try This:
SELECT daterow FROM datecolumn
WHERE TO_DATE(daterow,'HH24:MI') <= TO_DATE('12:00', 'HH24:MI');
In order to select all rows where time portion of the daterow column value is less than or equal to mid-day 12:00 you can use to_char() function to extract hour and minutes and to_number() to convert it to a number for further comparison:
-- sample of data. Just for the sake of demonstration
SQL> with t1(col) as(
2 select sysdate - to_dsinterval('P0DT3H') from dual union all
3 select sysdate - to_dsinterval('P0DT2H') from dual union all
4 select sysdate - to_dsinterval('P0DT1H') from dual union all
5 select sysdate + to_dsinterval('P0DT3H') from dual union all
6 select sysdate + to_dsinterval('-P2DT0H') from dual
7 )
8 select to_char(col, 'dd.mm.yyyy hh24:mi:ss') as res
9 from t1 t
10 where to_number(to_char(col, 'hh24mi')) <= 1200
11 ;
Result:
RES
-------------------
26.08.2013 08:10:59
26.08.2013 09:10:59
26.08.2013 10:10:59
24.08.2013 11:10:59
Sorry, but <= TO_DATE('12:00', 'HH24:MI') does not work. It does not extract the hour and minute from each date and compares it to 12:00. Instead it constructs the date representing high noon on the fisrt of the current month and compares each date to this date.
If you want to extract something from a date, use the extract function.
Attention: When using extract on a date, and want to extract hours, minutes or seconds, you have first to convert the date to a timestamp.
Example:
SELECT
extract(hour FROM cast(A AS TIMESTAMP)) AS h,
extract(MINUTE FROM cast(A AS TIMESTAMP)) AS m
FROM
DEMO
;
You can find a complete example on sqlfiddle. The example also shows that the to_date method doesn't work.