Find SUM of DATEDIFF on distinct pairs grouped by UserID? - sql

So I have a command that looks like this:
SELECT
UserID,
FacilityMMXID,
ScheduleDate,
StartTime,
EndTime
FROM TblPASchedule
WHERE UserID = 244 AND MONTH(ScheduleDate) = 03 AND Year(ScheduleDate) = 2017
The output looks like this
UserID FacilityMMXID ScheduleDate StartTime EndTime
----------- ------------- ------------ ---------------- ----------------
244 1 2017-03-17 01:00:00 05:00:00
244 2 2017-03-17 01:00:00 05:00:00
244 3 2017-03-17 01:00:00 05:00:00
244 4 2017-03-17 01:00:00 05:00:00
244 5 2017-03-17 01:00:00 05:00:00
244 6 2017-03-17 01:00:00 05:00:00
244 7 2017-03-17 01:00:00 05:00:00
244 8 2017-03-17 01:00:00 05:00:00
244 9 2017-03-17 01:00:00 05:00:00
244 10 2017-03-17 01:00:00 05:00:00
244 11 2017-03-17 01:00:00 05:00:00
244 12 2017-03-17 01:00:00 05:00:00
244 13 2017-03-17 01:00:00 05:00:00
244 14 2017-03-17 01:00:00 05:00:00
244 15 2017-03-17 01:00:00 05:00:00
244 1 2017-03-17 05:00:00 22:00:00
244 2 2017-03-17 05:00:00 22:00:00
244 3 2017-03-17 05:00:00 22:00:00
244 4 2017-03-17 05:00:00 22:00:00
244 5 2017-03-17 05:00:00 22:00:00
244 6 2017-03-17 05:00:00 22:00:00
244 7 2017-03-17 05:00:00 22:00:00
244 8 2017-03-17 05:00:00 22:00:00
244 9 2017-03-17 05:00:00 22:00:00
244 10 2017-03-17 05:00:00 22:00:00
244 11 2017-03-17 05:00:00 22:00:00
244 12 2017-03-17 05:00:00 22:00:00
244 13 2017-03-17 05:00:00 22:00:00
244 14 2017-03-17 05:00:00 22:00:00
244 15 2017-03-17 05:00:00 22:00:00
I left out the ID row as it really isn't important in this case.
Also- yes- I realize that this table is very very redundant- It isn't something I can currently fix as I am not allowed to- I can only work on getting the aforementioned summing function working.
The end goal is to pair off the distinct StartTime and EndTime pairs and then find the date difference of those- and then, for the entire month- find the sum of all the entries.
This is as far as I have gotten:
Using:
SELECT
UserID,
DATEDIFF(HOUR, StartTime, EndTime) AS 'Hours Worked'
FROM TblPASchedule WHERE UserID = 244 AND MONTH(ScheduleDate) = 03 AND Year(ScheduleDate) = 2017
GROUP BY UserId, StartTime, EndTime
I get the output to be:
UserID Hours Worked
----------- ------------
244 4
244 17
But I am not too sure about where I should go from here.
I eventually need to make it group these sums based on the UserIDs, but one step at a time I suppose. I am using a where clause to work with a single id for now...

This query gets all the distinct sets of UserID, Starttime and Endtime
;WITH CTE AS
(SELECT DISTINCT UserID, StartTime, EndTime FROM [dbo].[TblPASchedule])
SELECT SUM(DATEDIFF(MINUTE, StartTime, EndTime))/60.0 AS 'Hours Worked', UserID
FROM CTE GROUP BY UserID
RESULTS look like this
Hours Worked UserID
1.666666 19
1.233333 37
0.500000 38

Have you tried wrapping additional sub query on top of your groups?
SELECT UserId, SUM('Hours Worked') as 'Hours Worked' FROM (
SELECT
UserID,
DATEDIFF(HOUR, StartTime, EndTime) AS 'Hours Worked'
FROM TblPASchedule WHERE UserID = 244 AND MONTH(ScheduleDate) = 03 AND Year(ScheduleDate) = 2017
GROUP BY UserId, StartTime, EndTime
) AS temp
GROUP BY UserId

Related

Overlap in seconds between datetime range and a time range

I have a dataframe like this:
df11 = pd.DataFrame(
{
"Start_date": ["2018-01-31 12:00:00", "2018-02-28 16:00:00", "2018-02-27 22:00:00"],
"End_date": ["2019-01-31 21:45:00", "2019-03-24 22:00:00", "2018-02-28 01:00:00"],
}
)
Start_date End_date
0 2018-01-31 12:00:00 2019-01-31 21:45:00
1 2018-02-28 16:00:00 2019-03-24 22:00:00
2 2018-02-27 22:00:00 2018-02-28 01:00:00
I need to check the overlap time duration in specific periods in seconds. My expected results are like this:
Start_date End_date 12h-16h 16h-22h 22h-00h 00h-02h30
0 2018-01-31 12:00:00 2019-01-31 21:45:00 14400 20700 0 0
1 2018-02-28 16:00:00 2019-03-24 22:00:00 0 21600 0 0
2 2018-02-27 22:00:00 2018-02-28 01:00:00 0 0 7200 3600
I know it`s completely wrong and I´ve tried other solutions. This is one of my attempts:
df11['12h-16h']=np.where(df11['Start_date']<timedelta(hours=16, minutes=0, seconds=0) & df11['End_date']>timedelta(hours=12, minutes=0, seconds=0),(np.minimum(df11['End_date'],timedelta(hours=16, minutes=0, seconds=0)))-(np.maximum(df11['Start_date'],timedelta(hours=12, minutes=0, seconds=0)))

Processing data set into 30 minute values

I have a data set in the following format -
ID START_TIME END_TIME VAL
1 30-APR-2018 00:00:00 01-MAY-2018 00:00:00 423
2 01-MAY-2018 00:00:00 01-MAY-2018 17:15:00 455
3 01-MAY-2018 17:15:00 03-MAY-2018 00:00:00 455
Expected Output -
This data set should be broken down into 30 min interval values, however if there are records which are not at '00' or '30' minute point then they should be considered as part of this process (as shown for record with START_TIME/END_TIME = '17:15:00')
ID START_TIME END_TIME VAL
1 30-APR-2018 00:00:00 30-APR-2018 00:30:00 423
1 30-APR-2018 00:30:00 30-APR-2018 01:00:00 423
1 30-APR-2018 01:00:00 30-APR-2018 01:30:00 423
..
..
..
1 30-APR-2018 23:00:00 30-APR-2018 23:30:00 423
1 30-APR-2018 23:30:00 01-MAY-2018 00:00:00 423
2 01-MAY-2018 00:00:00 01-MAY-2018 00:30:00 455
2 01-MAY-2018 00:30:00 01-MAY-2018 01:00:00 455
..
..
..
..
2 01-MAY-2018 16:30:00 01-MAY-2018 17:00:00 455
2 01-MAY-2018 17:00:00 01-MAY-2018 17:15:00 455
3 01-MAY-2018 17:15:00 03-MAY-2018 17:30:00 455
3 01-MAY-2018 17:30:00 03-MAY-2018 18:00:00 455
..
..
..
3 02-MAY-2018 23:00:00 02-MAY-2018 23:30:00 455
3 02-MAY-2018 23:30:00 03-MAY-2018 00:00:00 455
What I have tried so far -
CREATE TABLE TESTT
(
ID NUMBER(8,3),
START_TIME DATE,
END_TIME DATE,
VAL NUMBER(8,3)
);
INSERT INTO TESTT VALUES (1, TO_DATE('30-APR-2018 00:00:00','DD-MON-YYYY HH24:MI:SS'), TO_DATE('01-MAY-2018 00:00:00','DD-MON-YYYY HH24:MI:SS'), 423);
INSERT INTO TESTT VALUES (2, TO_DATE('01-MAY-2018 00:00:00','DD-MON-YYYY HH24:MI:SS'), TO_DATE('01-MAY-2018 17:15:00','DD-MON-YYYY HH24:MI:SS'), 455);
INSERT INTO TESTT VALUES (3, TO_DATE('01-MAY-2018 17:15:00','DD-MON-YYYY HH24:MI:SS'), TO_DATE('03-MAY-2018 00:00:00','DD-MON-YYYY HH24:MI:SS'), 455);
COMMIT;
CREATE TABLE TESTT_OUTPUT AS
SELECT * FROM TESTT WHERE 1=2;
CREATE SEQUENCE TESTT_SEQ MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 NOCACHE NOORDER NOCYCLE NOPARTITION;
BEGIN
FOR R IN (SELECT * FROM TESTT)
LOOP
INSERT INTO TESTT_OUTPUT(id, START_TIME, END_TIME, VAL)
SELECT TESTT_SEQ.nextval, R.START_TIME + (LEVEL - 1)/48 AS START_TIME, R.START_TIME + LEVEL/48 AS END_TIME, R.VAL FROM
DUAL
CONNECT BY LEVEL <= ROUND((R.END_TIME - R.START_TIME)*48);
COMMIT;
END LOOP;
END;
/
SELECT * FROM TESTT_OUTPUT;
1 30-APR-2018 00:00:00 30-APR-2018 00:30:00 423
2 30-APR-2018 00:30:00 30-APR-2018 01:00:00 423
3 30-APR-2018 01:00:00 30-APR-2018 01:30:00 423
..
..
..
47 30-APR-2018 23:00:00 30-APR-2018 23:30:00 423
48 30-APR-2018 23:30:00 01-MAY-2018 00:00:00 423
49 01-MAY-2018 00:00:00 01-MAY-2018 00:30:00 455
50 01-MAY-2018 00:30:00 01-MAY-2018 01:00:00 455
..
..
..
82 01-MAY-2018 16:30:00 01-MAY-2018 17:00:00 455
83 01-MAY-2018 17:00:00 01-MAY-2018 17:30:00 455
84 01-MAY-2018 17:15:00 01-MAY-2018 17:45:00 455
85 01-MAY-2018 17:45:00 01-MAY-2018 18:15:00 455
86 01-MAY-2018 18:15:00 01-MAY-2018 18:45:00 455
87 01-MAY-2018 18:45:00 01-MAY-2018 19:15:00 455
..
..
..
141 02-MAY-2018 21:45:00 02-MAY-2018 22:15:00 455
142 02-MAY-2018 22:15:00 02-MAY-2018 22:45:00 455
143 02-MAY-2018 22:45:00 02-MAY-2018 23:15:00 455
144 02-MAY-2018 23:15:00 02-MAY-2018 23:45:00 455
145 02-MAY-2018 23:45:00 03-MAY-2018 00:15:00 455
With this approach any data with the minute value other than '00' or '30' will still be processed the same way by adding 30 mins to it and the final result does not have the point in time data for '00' or '30' minute value.
Hope this makes sense.
Any inputs on how to translate the data in the expected format will be extremely helpful. Thanks!
It seems rather inelegant, but this;
select id,
greatest(start_time,
adj_start_time + numtodsinterval(30 * (level - 1), 'MINUTE')) as start_time,
least(end_time,
adj_start_time + numtodsinterval(30 * level, 'MINUTE')) as end_time
from (
select id,
start_time,
end_time,
trunc(start_time, 'HH')
+ numtodsinterval(
case when extract(minute from cast(start_time as timestamp)) < 30 then 0
else 30
end, 'MINUTE') as adj_start_time
from testt
)
connect by level <= ceil((end_time - start_time - 1/86400) / (30/1440))
and prior id = id
and prior dbms_random.value is not null
order by id, start_time;
seems to get the result you want, generating 145 rows:
ID START_TIME END_TIME
---------- ------------------- -------------------
1 2018-04-30 00:00:00 2018-04-30 00:30:00
1 2018-04-30 00:30:00 2018-04-30 01:00:00
1 2018-04-30 01:00:00 2018-04-30 01:30:00
...
1 2018-04-30 22:30:00 2018-04-30 23:00:00
1 2018-04-30 23:00:00 2018-04-30 23:30:00
1 2018-04-30 23:30:00 2018-05-01 00:00:00
2 2018-05-01 00:00:00 2018-05-01 00:30:00
2 2018-05-01 00:30:00 2018-05-01 01:00:00
2 2018-05-01 01:00:00 2018-05-01 01:30:00
...
2 2018-05-01 16:00:00 2018-05-01 16:30:00
2 2018-05-01 16:30:00 2018-05-01 17:00:00
2 2018-05-01 17:00:00 2018-05-01 17:15:00
3 2018-05-01 17:15:00 2018-05-01 17:30:00
3 2018-05-01 17:30:00 2018-05-01 18:00:00
3 2018-05-01 18:00:00 2018-05-01 18:30:00
...
3 2018-05-02 22:30:00 2018-05-02 23:00:00
3 2018-05-02 23:00:00 2018-05-02 23:30:00
3 2018-05-02 23:30:00 2018-05-03 00:00:00
The inline view gets the real columns plus the nominal 30-minute window for the start -i.e., for 17:15 it gets 17:00, as adj_start_time. The hierarchical query adds 30-minute intervals to that, and uses least and greatest to get the original start/end time if they are not exactly on the half-hour.
For your insert you can replace the original ID with an analytic row_number() rather than using a sequence, and include the val:
insert into testt_output(id, start_time, end_time, val)
select row_number() over (order by id, level),
greatest(start_time,
adj_start_time + numtodsinterval(30 * (level - 1), 'MINUTE')) as start_time,
least(end_time,
adj_start_time + numtodsinterval(30 * level, 'MINUTE')) as end_time,
val
from (
select id,
start_time,
end_time,
val,
trunc(start_time, 'HH')
+ numtodsinterval(
case when extract(minute from cast(start_time as timestamp)) < 30 then 0
else 30
end, 'MINUTE') as adj_start_time
from testt
)
connect by level <= ceil((end_time - start_time - 1/86400) / (30/1440))
and prior id = id
and prior dbms_random.value is not null;
145 rows inserted.
select * from testt_output;
ID START_TIME END_TIME VAL
---------- ------------------- ------------------- ----------
1 2018-04-30 00:00:00 2018-04-30 00:30:00 423
2 2018-04-30 00:30:00 2018-04-30 01:00:00 423
...
47 2018-04-30 23:00:00 2018-04-30 23:30:00 423
48 2018-04-30 23:30:00 2018-05-01 00:00:00 423
49 2018-05-01 00:00:00 2018-05-01 00:30:00 455
50 2018-05-01 00:30:00 2018-05-01 01:00:00 455
...
82 2018-05-01 16:30:00 2018-05-01 17:00:00 455
83 2018-05-01 17:00:00 2018-05-01 17:15:00 455
84 2018-05-01 17:15:00 2018-05-01 17:30:00 455
85 2018-05-01 17:30:00 2018-05-01 18:00:00 455
...
144 2018-05-02 23:00:00 2018-05-02 23:30:00 455
145 2018-05-02 23:30:00 2018-05-03 00:00:00 455
db<>fiddle demo.

Total time calculation in a sql query for a day where time in 24 hour format as hhmm

I have a table with date(date), left time(varchar2(4)) and arrival time(varchar2(4)). Time taken is in 24 hour format as hhmm. If a person travel 3 times a day, what will be the query to calculate total travel time in a day?
I am using oracle 11g. Kindly help. Thank you.
Convert the value to a number and report in minutes:
select to_number(substring(time, 1, 2))*60 + to_number(substring(time, 3, 2)) as minutes
Your query would look something like:
select person, sum(to_number(substring(time, 1, 2))*60 + to_number(substring(time, 3, 2))) as minutes
from t
group by person;
I see no reason to convert this back to a string -- or to even store the value as a string instead of as a number. But if you need to, you can reverse the process to get a string.
There are 2 answers, If you want to sum time only on date then it can be done as:-
select curr_date,
sum(24 * (to_date(arrival_time, 'HH24:mi:ss')- to_date(left_time, 'HH24:mi:ss'))) as difference
from sql_prac group by curr_date,arrival_time,left_time;
The sample output is as follows:-
select curr_date,left_time,arrival_time from sql_prac;
CURR_DATE LEFT_TIME ARRIVAL_TIME
--------- -------------------- --------------------
30-JUN-17 00:00:00 15:00:00
30-JUL-17 03:30:00 11:30:00
30-AUG-17 03:00:00 12:30:00
30-SEP-17 04:00:00 17:00:00
30-JUN-17 00:00:00 15:00:00
30-JUL-17 03:30:00 11:30:00
30-AUG-17 03:00:00 12:30:00
30-SEP-17 04:00:00 17:00:00
30-SEP-17 04:00:00 17:00:00
9 rows selected
select curr_date,sum(24 * (to_date(arrival_time, 'HH24:mi:ss')- to_date(left_time, 'HH24:mi:ss'))) as difference
from sql_prac group by curr_date,arrival_time,left_time;
CURR_DATE DIFFERENCE
--------- ----------
30-JUN-17 30
30-JUL-17 16
30-SEP-17 39
30-AUG-17 19
If you want to sum it by person and date then it can be done as:-
select dept,curr_date,sum(24 * (to_date(arrival_time, 'HH24:mi:ss')- to_date(left_time, 'HH24:mi:ss'))) as difference
from sql_prac group by dept,curr_date,arrival_time,left_time order by Dept;
The sample output is as follows:-
Data in table is:-
select dept,curr_date,left_time,arrival_time from sql_prac;
DEPT CURR_DATE LEFT_TIME ARRIVAL_TIME
-------------------- --------- -------------------- --------------------
A 30-SEP-17 04:00:00 17:00:00
B 30-SEP-17 04:00:00 17:00:00
C 30-AUG-17 03:00:00 12:30:00
D 30-DEC-17 04:00:00 17:00:00
A 30-SEP-17 04:00:00 17:00:00
B 30-JUL-17 03:30:00 11:30:00
C 30-AUG-17 03:00:00 12:30:00
D 30-SEP-17 04:00:00 17:00:00
R 30-SEP-17 04:00:00 17:00:00
Data fetched using the query
select dept,curr_date,sum(24 * (to_date(arrival_time, 'HH24:mi:ss')- to_date(left_time, 'HH24:mi:ss'))) as difference
from sql_prac group by dept,curr_date,arrival_time,left_time order by Dept;
DEPT CURR_DATE DIFFERENCE
-------------------- --------- ----------
A 30-SEP-17 26
B 30-JUL-17 8
B 30-SEP-17 13
C 30-AUG-17 19
D 30-SEP-17 13
D 30-DEC-17 13
R 30-SEP-17 13

from 15 minutes interval to hourly interval counts

am using excel sheet to display data from sql with this query
SELECT itable.Timestamp, itable.Time,
Sum(itable.CallsOffered)AS CallsOffered, Sum(itable.CallsAnswered)AS CallsAnswered, Sum(itable.CallsAnsweredAftThreshold)AS CallsAnsweredAftThreshold,
sum(CallsAnsweredDelay)AS CallsAnsweredDelay
FROM tablename itable
WHERE
(itable.Timestamp>=?) AND (itable.Timestamp<=?) AND
(itable.Application in ('1','2','3','4'))
GROUP BY itable.Timestamp, itable.Time
ORDER BY itable.Timestamp, itable.Time
and i get a data with an interval of 15 minutes like this :
Timestamp Time CallsOffered CallsAnswered CallsAnsweredAftThreshold CallsAnsweredDelay
6/1/2014 0:00 00:00 0 1 1 52
6/1/2014 0:15 00:15 3 1 1 23
6/1/2014 0:30 00:30 3 3 2 89
6/1/2014 0:45 00:45 0 0 0 0
6/1/2014 1:00 01:00 0 0 0 0
6/1/2014 1:15 01:15 4 1 1 12
6/1/2014 1:30 01:30 1 1 1 39
6/1/2014 1:45 01:45 0 0 0 0
6/1/2014 2:00 02:00 2 1 0 7
6/1/2014 2:15 02:15 1 1 1 80
6/1/2014 2:30 02:30 3 2 2 75
6/1/2014 2:45 02:45 0 0 0 0
6/1/2014 3:00 03:00 0 0 0 0
and i want to convert the interval from being 15 minutes to hourly interval
like this
2014-07-01 00:00:00.000
2014-07-01 01:00:00.000
2014-07-01 02:00:00.000
2014-07-01 03:00:00.000
2014-07-01 04:00:00.000
2014-07-01 05:00:00.000
2014-07-01 06:00:00.000
2014-07-01 07:00:00.000
2014-07-01 08:00:00.000
2014-07-01 09:00:00.000
2014-07-01 10:00:00.000
2014-07-01 11:00:00.000
2014-07-01 12:00:00.000
2014-07-01 13:00:00.000
2014-07-01 14:00:00.000
the query i came up with is :
select
timestamp = DATEADD(hour,datediff(hour,0,app.Timestamp),0),
Sum(app.CallsOffered)AS CallsOffered,
Sum(app.CallsAnswered)AS CallsAnswered,
Sum(app.CallsAnsweredAftThreshold)AS CallsAnsweredAftThreshold,
sum(CallsAnsweredDelay)AS CallsAnsweredDelay,
max(MaxCallsAnsDelay) as MaxCallsAnsDelay ,
max(app.MaxCallsAbandonedDelay)as MaxCallsAbandonedDelay
from tablename app
where Timestamp >='2014-7-1' AND timestamp<='2014-7-2' and
(app.Application in (
'1',
'2',
'3',
'4')
group by DATEADD(hour,datediff(hour,0,Timestamp),0)
order by Timestamp;
i get the result i want when i run in in Microsoft Sql server Managment studio
but it gives me a long error when i try running the same query in Microsoft Query in excel the error is like i cant start with timestamp
and that its giving me error for DATEADD ,DATEDIFF
so is there something i should change in my query or anything i can do to get an hourly count interval instead of 15 minutes count interval as ive shown
and thank you in advance

How to Split Time and calculate time difference in sql server 2005?

i want to split the time and calculate time difference using sql server 2005
my default output is like this:
EnrollNo AttDateFirst AttDateLast
111 2011-12-09 08:46:00.000 2011-12-09 08:46:00.000
112 2011-12-09 08:40:00.000 2011-12-09 17:30:00.000
302 2011-12-09 09:00:00.000 2011-12-09 18:30:00.000
303 2011-12-09 10:00:00.000 2011-12-09 18:35:00.000
I want my new output to be like this:
Enroll No ..... FirtTime LastTime Time Diff
111 ..... 8:46:00 8:45:00 00:00:00
112 ..... 8:30:00 17:30:00 9:00:00
302 ..... 9:00:00 18:30:00 9:30:00
303 ..... 10:00:00 18:35:00 8:35:00
You can use this query:
select EnrollNo, convert(varchar, AttDateFirst, 8) as FirstTime,
convert(varchar, AttDateLast, 8) as LastTime,
convert(varchar, AttDateLast - AttDateFirst, 8) as [Time Diff]
from YourTable
to return the following results:
EnrollNo FirstTime LastTime Time Diff
----------- ------------------------------ ------------------------------ ------------------------------
111 08:46:00 08:46:00 00:00:00
112 08:30:00 17:30:00 09:00:00
302 09:00:00 18:30:00 09:30:00
303 10:00:00 18:35:00 08:35:00
you can use
select DATEDIFF(day,2007-11-30,2007-11-20) AS NumberOfDays,
DATEDIFF(hour,2007-11-30,2007-11-20) AS NumberOfHours,
DATEDIFF(minute,2007-11-30,2007-11-20) AS NumberOfMinutes from
test_table
to split u can use
substring(AttDateFirst,charindex(' ',AttDateFirst)+1 ,
len(AttDateFirst)) as [FirstTime]