Of course - thinking about this a bit more I found another issue...if multiple rows can be covered by previous rows the calculation will be incorrect.
Declare @Source Table (
UserID tinyint
, LessonID tinyint
, DateStarted datetime
, DateEnded datetime
);
Insert Into @Source (
UserID
, LessonID
, DateStarted
, DateEnded
)
Values (1, 4, '20180606 09:00:00', '20180606 11:00:00') -- 120 minutes
, (1, 4, '20180606 09:01:00', '20180606 09:30:00') -- overlapped
, (1, 4, '20180606 09:02:00', '20180606 09:35:00') -- overlapped
, (1, 4, '20180606 09:03:00', '20180606 09:40:00') -- overlapped
, (1, 4, '20180606 09:04:00', '20180606 11:15:00') -- 15 minutes
, (1, 4, '20180606 09:15:00', '20180606 11:30:00') -- 15 minutes
, (1, 4, '20180606 10:00:00', '20180606 10:30:00') -- overlapped
, (1, 4, '20180607 10:00:00', '20180607 10:30:00'); -- 30 minutes
-- Total 180 minutes
With getMaxDates
As (
Select s.UserID
, s.LessonID
, s.DateStarted
, s.DateEnded
, MaxDateEnded = max(s.DateEnded) over(Partition By s.UserID, s.LessonID
Order By s.DateStarted, s.DateEnded
Rows Between Unbounded Preceding And Current Row)
From @Source s
)
, getNextStarted
As (
Select md.UserID
, md.LessonID
, md.DateStarted
, md.DateEnded
, md.MaxDateEnded
, NextDateStarted = lead(md.DateStarted, 1, md.DateEnded) over(Partition By md.UserID, md.LessonID
Order By md.DateStarted, md.DateEnded)
From getMaxDates md
Where md.MaxDateEnded <= md.DateEnded
)
Select ns.UserID
, ns.LessonID
, TotalTime = sum(datediff(minute, ns.DateStarted, iif(ns.NextDateStarted < ns.DateEnded, ns.NextDateStarted, ns.DateEnded)))
From getNextStarted ns
Group By
ns.UserID
, ns.LessonID;
This change addresses that issue and resolves for all scenarios. In this one we get the max date ended from any previous rows - then we eliminate any rows where the date ended is less than the max date ended - now we can summarize the difference for each row.