formatting total time spent using extract - sql

I'm open to any suggestions, so long as I get something resembling the output at the bottom of the post, TIA!
Can I get some help with this sql fiddle: http://sqlfiddle.com/#!4/c51c5/1
SCHEMA
create table history(
clockingGroup varchar2(5)
, startTime timestamp
, endTime timestamp);
insert into history
(clockingGroup, startTime, endTime)
values
('grp1', '01-dec-2015 1:00:00.000000', '01-dec-2015 1:10:10.000000');
insert into history
(clockingGroup, startTime, endTime)
values
('grp2', '01-dec-2015 1:10:10.000000', '01-dec-2015 1:20:20.000000');
insert into history
(clockingGroup, startTime, endTime)
values
('grp1', '01-dec-2015 1:20:20.000000', '01-dec-2015 1:30:35.000000');
insert into history
(clockingGroup, startTime, endTime)
values
('grp3', '01-dec-2015 1:30:35.000000', '01-dec-2015 1:35:00.000000');
SQL
select
extract(hour from (sum(cast(endTime as date) - cast(startTime as date)))) || ' Hours '
|| extract(minute from (sum(cast(endTime as date) - cast(startTime as date)))) || ' Minutes '
|| extract(second from (sum(cast(endTime as date) - cast(startTime as date)))) || ' Seconds'
as totalTime
, clockingGroup
from
history
group by
clockingGroup
Current Error
ORA-30076: invalid extract field for extract source
My desired output is:
clockingGroup | totalTime
grp1 | 0 Hours 20 Minutes 25 Seconds
grp2 | 0 Hours 10 Minutes 10 Seconds
grp3 | 0 Hours 4 Minutes 25 Seconds

You are using the built ins in the wrong order. Your original query casts your timestamps to dates. When you subtract dates from each other you get a number.
In the query below it subtracts a timestamp from a timestamp which yields an INTERVAL. You cannot extract the hour from a number but you can from an INTERVAL.
SELECT clockingGroup.
SUM(extract(DAY FROM endtime-starttime)) ||' '||
SUM(extract(HOUR FROM endtime-starttime)) ||' '||
SUM(extract(MINUTE FROM endtime-starttime)) ||' '||
SUM(extract(SECOND FROM endtime-starttime)) AS TOTALTIME,
from
history
group by
clockingGroup
I see you have added another method using numtodsinterval. You are still converting timestamps to dates which you don't need to do if you want precision.
This query is more complicated as I try and show how you take the difference and count all the intervals as seconds, sum them and then break it apart into hours/minutes/seconds
SELECT CLOCKINGGROUP, TO_CHAR(TRUNC(SUMTOTALSECONDS/3600),'FM9900') || ' Hours ' ||
TO_CHAR(TRUNC(MOD(SUMTOTALSECONDS,3600)/60),'FM00') || ' Minutes ' ||
TO_CHAR(MOD(SUMTOTALSECONDS,60),'FM00') || ' Seconds'
FROM(
SELECT clockinggroup, TRUNC(SUM(TOTALSECONDS),0) AS SUMTOTALSECONDS
FROM (
SELECT clockinggroup,
EXTRACT (DAY FROM (EndTime-StartTime))*24*60*60 +
EXTRACT (HOUR FROM (EndTime-StartTime))*60*60 +
EXTRACT (MINUTE FROM (EndTime-StartTime))*60 +
EXTRACT (SECOND FROM (EndTime-StartTime))/60 AS TOTALSECONDS
FROM history)
group by
clockingGroup)
ORDER BY 1;

Related

teradata converting timestamp to time

I'm struggling with something that seems very obvious on first sight and most probably I'm overlooking something stupid but anyway.
I need to calculate the difference between timestamp fields and convert the result (which is as I assume a timestamp ) into the number of days and the elapsed time.
I can't seem to get the cast(xx to time) wright
I made a small example
SELECT
Cast(Cast( c_date AS CHAR(10)) || ' ' || Cast( c_time AS CHAR(10)) AS TIMESTAMP(6)) AS starttime ,
Cast(Cast( e_date AS CHAR(10)) || ' ' || Cast( e_time AS CHAR(10)) AS TIMESTAMP(6)) AS endtm,
(endtm - starttime) DAY(4) TO SECOND AS difftime
,Extract(DAY From difftime) --> gives the days
,Cast(difftime AS TIME)
,Extract (HOUR From difftime)
FROM (
SELECT Cast(Current_Timestamp AS DATE) c_date,
Cast(Current_Timestamp(0) AS TIME(0)) c_time,
Cast(Current_Timestamp + Random(1,10) * INTERVAL '1' DAY AS DATE) e_date,
Cast(Current_Timestamp(0) + Random(1,24) * INTERVAL '1' HOUR + Random(1,60) * INTERVAL '1' MINUTE AS TIME(0)) e_time
) t
,Cast(difftime AS TIME) gives me the trouble
the extract day and hour works => the difftime is really a timestamp (is it ? and if not what kind of field is it then ? ).
some advise would be nice :-)

getting time format difference of two times

I am trying to get the time format difference of two different times in firebird sql. I tried subtracting the two times but the result is not in time format.
TIME_IN TIME,
TIME_OUT TIME,
DIFFERENCE TIME
SELECT
TIME_IN,
TIME_OUT,
TIME_OUT - TIME_IN
Sample Data
TIME_IN = 7:00
TIME_OUT = 12:00
12:00 - 7:00
my expected output is 5:00
also tried using DATEDIFF but my result is not in time format
DATEDIFF (HOUR, TIME_IN, TIME_OUT)
Something like this:
SELECT
CAST(DATEDIFF(HOUR, CAST(EXTRACT(HOUR FROM CAST(CAST(:TIME_IN as varchar(5)) as time)) || ':00' as TIME), CAST(EXTRACT(HOUR FROM CAST(CAST(:TIME_OUT as varchar(5)) as time)) || ':00' as TIME))
|| ':' ||
DATEDIFF(MINUTE, CAST('00:' || EXTRACT(MINUTE FROM CAST(CAST(:TIME_IN as varchar(5))as time)) as TIME), CAST('00:' || EXTRACT(MINUTE FROM CAST(CAST(:TIME_OUT as varchar(5)) as time)) as TIME)) as TIME)
FROM sth
The result of DATEDIFF is an integral value for the specified type. So the result of DATEDIFF(HOUR, '07:00', '12:00') is 5, and not 5:00.
The SQL TIME datatype is only for a 24 hour time within a day, it is not for measuring duration.
If for some reason you want to format it as a time, you will need to do that yourself. For example, by taking the difference in minutes, and then calculating the correct representation in hours and minutes.

SQL View Query need time interval calculation between 2 dates

I have below View Query. While calculating time interval it only display time interval if check Out is for same date. For example if i check in on 11/12/2017 then it i have to check out with same date 11/12/201 n order to calculate time Interval.
But i want to modify it like if i checkout on next day (after 12:00 AM midnight) it should also calculate the time interval.can some help me to modify query to get the desired results?
Query:
ALTER VIEW [dbo].[TimeAttendanceQuery]
AS
SELECT TOP (100) PERCENT
dbo.AxPerson.Name,
dbo.AxPerson.IdNumber AS EmployeeID,
dbo.TimeAttendance.Badge,
dbo.AxPerson.Id,
MIN(dbo.TimeAttendance.EventTime) AS EntryTime,
MAX(dbo.TimeAttendance.EventTime) AS ExitTime,
CAST(DATEDIFF(second, MIN(dbo.TimeAttendance.EventTime), MAX(dbo.TimeAttendance.EventTime)) / 60 / 60 / 24 AS NVARCHAR(50)) +
':' + CAST(DATEDIFF(second, MIN(dbo.TimeAttendance.EventTime), MAX(dbo.TimeAttendance.EventTime)) / 60 / 60 % 24 AS NVARCHAR(50)) + ':' + CAST(DATEDIFF(second, MIN(dbo.TimeAttendance.EventTime), MAX(dbo.TimeAttendance.EventTime)) / 60 % 60 AS NVARCHAR(50))
AS TimeInterval,
dbo.TimeAttendance.Event,
dbo.AxPerson.Type AS ShitType,
dbo.AxPerson.ShiftDesc,
CONVERT(Varchar,dbo.TimeAttendance.EventTime, 101) AS EventTIME
FROM
dbo.AxPerson
INNER JOIN dbo.TimeAttendance ON dbo.AxPerson.Name = dbo.TimeAttendance.Name
GROUP BY dbo.AxPerson.Name, dbo.AxPerson.IdNumber, dbo.TimeAttendance.Badge, CONVERT(Varchar, dbo.TimeAttendance.EventTime, 101), dbo. AxPerson.ShiftDesc, dbo.AxPerson.Id, dbo.TimeAttendance.Event,dbo.AxPerson.Type
ORDER BY dbo.AxPerson.Name, EventTime DESC
GO
I'm not sure about the algorithm you posted, but if you want to get the time difference from two datetimes you can cast the subtraction as time. This works for less than 24 hours. If you also want the number of days (I think this is only good for less than a year), then you can do the datepart-day of the difference.
For example:
DECLARE #starttime datetime = '2017-11-12 010:20:00'
DECLARE #endtime datetime = '2017-11-13 08:00:00'
SELECT DATEPART(DAY, #endtime - #starttime) - 1 [Days Passed]
,CAST(#endtime - #starttime as time(0)) [Time Passed]
--WHERE the (0) in time(0) is for the milliseconds to return.
Gives output:
Days Passed Time Passed
0 21:40:00
If you don't care about the days, then your code could be modified like this:
ALTER VIEW [dbo].[TimeAttendanceQuery]
AS
SELECT Name, EmployeeID, Badge, Id, EntryTime,
CAST(ExitTime - EntryTime as time(0)) [TimeInterval],
Event, ShiftType, ShiftDesc
,CONVERT(Varchar, EventTime, 101) AS EventTIME
FROM (
SELECT
dbo.AxPerson.Name,
dbo.AxPerson.IdNumber AS EmployeeID,
dbo.TimeAttendance.Badge,
dbo.AxPerson.Id,
MIN(dbo.TimeAttendance.EventTime) AS EntryTime,
MAX(dbo.TimeAttendance.EventTime) AS ExitTime,
dbo.TimeAttendance.Event,
dbo.AxPerson.Type AS ShiftType,
dbo.AxPerson.ShiftDesc,
dbo.TimeAttendance.EventTime
FROM dbo.AxPerson INNER JOIN dbo.TimeAttendance
ON dbo.AxPerson.Name = dbo.TimeAttendance.Name
GROUP BY
dbo.AxPerson.Name,
dbo.AxPerson.IdNumber,
dbo.TimeAttendance.Badge,
dbo.AxPerson.Id,
dbo.TimeAttendance.Event,
dbo.AxPerson.Type
dbo.AxPerson.ShiftDesc,
dbo.TimeAttendance.EventTime,
) AS dT

Get data in range using oracle

Please help me to solve this.
I have a table that contain users check in (checktype = I) and check out (checktype = 0) time everyday, and I would like to get the total amount of check in time per user which occur > 08:00 AM in a specific date range.
I am using the query below, but only handle one day per query not in a range, so I have to loop using javascript to get the amount of delay ( > 08:00 AM) per user for example from 01/06/2012 to 06/06/2012
Please help me to get the amount (count) check in time > 08:00 AM per user (ex: userid 708) from ex:01/06/2012 to 06/06/2012 in a single query.
with tt as
(
select TO_DATE('01/06/2012 08:00:00','dd/mm/yyyy hh24:mi:ss') date1 ,
checktime date2
from
checkinout
where
userid = '708' and
to_char(checktime,'dd/mm/yyyy') = '01/06/2012' and
checktype='I' -- checktype I is check in
) , t2 as
(
select numtodsinterval(date2 - date1,'day') dsinterval from tt
)
select extract(hour from dsinterval) || ' hours ' ||
extract(minute from dsinterval) || ' minutes ' ||
round(extract(second from dsinterval)) || ' seconds' late from t2
I assume you wanted to get how many hours late (i.e. after 08:00) the checkins have been done:
with t2 as (
select userid
,numtodsinterval(sum(checktime - (trunc(checktime)+8/24)),'day') dsinterval
,count(1) cnt
from checkinout
where userid='708'
and checktime > trunc(checktime)+8/24
and trunc(checktime) between to_date('01/06/2012','DD/MM/YYYY') and to_date('06/06/2012','DD/MM/YYYY')
and checktype = 'I'
group by userid
)
select extract(hour from dsinterval) || ' hours ' ||
extract(minute from dsinterval) || ' minutes ' ||
round(extract(second from dsinterval)) || ' seconds' late
,cnt
from t2;
See http://sqlfiddle.com/#!4/c4670/11 for my test case.
edit: added column "cnt" to show how many times
Consider the following example on base of this you can write your own logic
WITH tbl AS
(SELECT SYSDATE dt
FROM DUAL
UNION
SELECT SYSDATE + (1 + (10 / 1440))
FROM DUAL
UNION
SELECT SYSDATE + (2 + (12 / 1440))
FROM DUAL
UNION
SELECT SYSDATE + (3 + (13 / 1440))
FROM DUAL
UNION
SELECT SYSDATE + (6 + (15 / 1440))
FROM DUAL
UNION
SELECT SYSDATE + (8 + (18 / 1440))
FROM DUAL)
SELECT EXTRACT (HOUR FROM dsinterval)
|| ' hours '
|| EXTRACT (MINUTE FROM dsinterval)
|| ' minutes '
|| ROUND (EXTRACT (SECOND FROM dsinterval))
|| ' seconds' late
FROM (SELECT NUMTODSINTERVAL (dt1 - dt2, 'day') dsinterval
FROM (SELECT TO_DATE (TO_CHAR (dt, 'DD/MM/YYYY') || ' 08:00:00',
'DD/MM/YYYY HH24:MI:SS'
) dt1,
TO_DATE (TO_CHAR (dt, 'DD/MM/YYYY HH24:MI:SS'),
'DD/MM/YYYY HH24:MI:SS'
) dt2
FROM tbl
WHERE dt BETWEEN SYSDATE + 2 AND SYSDATE + 5))
As per code you can write like
SELECT EXTRACT (HOUR FROM dsinterval)
|| ' hours '
|| EXTRACT (MINUTE FROM dsinterval)
|| ' minutes '
|| ROUND (EXTRACT (SECOND FROM dsinterval))
|| ' seconds' late
FROM (SELECT NUMTODSINTERVAL (dt1 - dt2, 'day') dsinterval
FROM (SELECT TO_DATE (TO_CHAR (checktime , 'DD/MM/YYYY') || ' 08:00:00',
'DD/MM/YYYY HH24:MI:SS'
) dt1,
TO_DATE (checktime, 'DD/MM/YYYY HH24:MI:SS') dt2
FROM checkinout
WHERE checktime BETWEEN start_date AND end_date
AND checktype='I'))

Writing an Oracle function to get the time of an event back if its not in another event

Let me be explain what I want: There are some components which can fail due to some reasons and they have priorities. Now, what I want is that if an event occurs and its priority is low, I will pass its start time and end time to the function and see if there is some other high priority component that was there in that period of time. If there was, then there are four cases:
If the low priority event is in the timing of high priority event then time is 0.
If the end time of the event is in the high priority but start time is out side the high priority then the time outside the event.
If the start time of the event is in the high priority but end time is out side the high priority then the time outside the event.
both start and end are out means high priority comes in between the low priority event.
Example: Assume that every event has high priority. I am sending the start time and end time, e.g. 12:41:01 and 12:49:01
component start time end time
1 12:40:01 12:50:01 result will be 0 because it's between the start & end
2 12:40:01 12:48:01 result will be 1 minute
3 12:43:01 12:50:01 result will be 2 minutes
4 12:43:01 12:44:01 result will be 7 minutes
I want the function to send me back the time in seconds. I have to compare it with every component all the time, and I don't know how to do it in a function only function not procedure.
Given the following table definition
CREATE TABLE EVENT_OCCURRENCE
(COMPONENT NUMBER PRIMARY KEY,
PRIORITY VARCHAR2(6) NOT NULL
CHECK(PRIORITY IN ('HIGH', 'MEDIUM', 'LOW')),
START_TIME DATE NOT NULL,
END_TIME DATE NOT NULL);
with the following data
INSERT INTO EVENT_OCCURRENCE (COMPONENT, PRIORITY, START_TIME, END_TIME)
VALUES (1, 'HIGH', TRUNC(SYSDATE) + INTERVAL '0 12:40:01' DAY TO SECOND, TRUNC(SYSDATE) + INTERVAL '0 12:50:01' DAY TO SECOND);
INSERT INTO EVENT_OCCURRENCE (COMPONENT, PRIORITY, START_TIME, END_TIME)
VALUES (2, 'HIGH', TRUNC(SYSDATE) + INTERVAL '0 12:45:01' DAY TO SECOND, TRUNC(SYSDATE) + INTERVAL '0 12:48:01' DAY TO SECOND);
INSERT INTO EVENT_OCCURRENCE (COMPONENT, PRIORITY, START_TIME, END_TIME)
VALUES (3, 'HIGH', TRUNC(SYSDATE) + INTERVAL '0 12:39:01' DAY TO SECOND, TRUNC(SYSDATE) + INTERVAL '0 12:46:01' DAY TO SECOND);
INSERT INTO EVENT_OCCURRENCE (COMPONENT, PRIORITY, START_TIME, END_TIME)
VALUES (4, 'HIGH', TRUNC(SYSDATE) + INTERVAL '0 12:38:01' DAY TO SECOND, TRUNC(SYSDATE) + INTERVAL '0 12:55:01' DAY TO SECOND);
the following procedure will NOT give the results you asked for, but given that your explanation was a bit lacking in detail I think this is the best you can hope for. It should give you something to start from to get what you think you want:
CREATE OR REPLACE PROCEDURE PRINT_INTERSECTING_OCCURRENCES(dtEvent_start IN DATE,
dtEvent_end IN DATE) IS
BEGIN
DBMS_OUTPUT.PUT_LINE('dtEvent_start=' || TO_CHAR(dtEvent_start, 'DD-MON-YYYY HH24:MI:SS') ||
' dtEvent_end=' || TO_CHAR(dtEvent_end, 'DD-MON-YYYY HH24:MI:SS'));
FOR aRow IN (SELECT E.*,
CASE
WHEN dtEvent_start >= E.START_TIME
AND dtEvent_end <= E.END_TIME
THEN
0
WHEN dtEvent_start < E.START_TIME
AND dtEvent_end BETWEEN E.START_TIME AND E.END_TIME
THEN
(E.START_TIME - dtEvent_start) * (24 * 60 * 60)
WHEN dtEvent_start BETWEEN E.START_TIME AND E.END_TIME
AND dtEvent_end > E.END_TIME
THEN
(dtEvent_end - E.END_TIME) * (24 * 60 * 60)
WHEN dtEvent_start > E.END_TIME
OR dtEvent_end < E.START_TIME
THEN
(dtEvent_end - dtEvent_start) * (24 * 60 * 60)
ELSE
((E.START_TIME - dtEvent_start) * (24 * 60 * 60))
+ ((dtEvent_end - E.END_TIME) * (24 * 60 * 60))
END AS TIME_DIFF
FROM EVENT_OCCURRENCE E
WHERE E.PRIORITY = 'HIGH')
LOOP
DBMS_OUTPUT.PUT_LINE('COMPONENT=' || aRow.COMPONENT ||
' PRIORITY=' || aRow.PRIORITY ||
' START_TIME=' || TO_CHAR(aRow.START_TIME, 'DD-MON-YYYY HH24:MI:SS') ||
' END_TIME=' || TO_CHAR(aRow.END_TIME, 'DD-MON-YYYY HH24:MI:SS') ||
' TIME_DIFF=' || aRow.TIME_DIFF);
END LOOP;
END PRINT_INTERSECTING_OCCURRENCES;
Share and enjoy.
The description doesn't seem to make sense, but I think this is what you might be looking for (assuming start_time_in and end_time_in are the names of your input variables).
select component, ((start_time - least(start_time, start_time_in)) + (greatest(end_time, end_time_in) - end_time)) * 24*60*60 seconds_outside_window
from table