Reputation: 9439
Trying to write a query in SQL for the following: an event has a start/end date/time. Users are available for certain times. How can I find the total time a user is available for a particular event?
Example:
--Event--
eventID eventStart eventEnd
1 2012-10-10 15:00 2012-10-10 18:00
--Available--
userID availStart availEnd
64 2012-10-10 10:00 2012-10-10 16:00
64 2012-10-10 16:30 2012-10-10 16:40
64 2012-10-10 16:55 2012-10-10 22:00
The user is free for 135 minutes (60 mins from 15:00-16:00, 10 mins from 16:30-16:40, 65 mins from 16:55-18:00).
Some help writing the SQL would be really helpful, finding this one tricky!
Upvotes: 1
Views: 263
Reputation: 10976
Tested it now: http://sqlfiddle.com/#!3/a4e7a/2
I've assumed a user table. There's lots of scope for performance improvement. E.g by adding a where clause that eliminates ranges that don't overlap. It'll probably also be faster if you replace the function with a hideous case statement.
The tricky bit is figuring out the algorithm for how much of two timespans overlap. I always find it useful to draw pictures of the cases:
Case 1
|------|
|=======|
Case 2
|------|
|======|
Case 3
|-------|
|===|
and the equivalent with the orders reversed.
It turns out the overlap is the minimum of the two end times minus the maximum of the two start times. (If negative there is no overlap). I always have to check all the cases to re-convince myself of this.
-- Function that determines how many minutes of overlap there are between two timespans
Create Function dbo.MinutesOverlap(
@Start1 as datetime, @End1 as datetime, @Start2 as datetime, @End2 as datetime
) Returns int As
Begin
Declare
@MaxStart As datetime,
@MinEnd As datetime,
@Ret int = 0
Set @MaxStart = Case When @Start1 > @Start2 Then @Start1 Else @Start2 End
Set @MinEnd = Case When @End1 > @End2 Then @End2 Else @End1 End
If @MaxStart < @MinEnd
Set @Ret = DateDiff(Minute, @MaxStart, @MinEnd)
Return @Ret
End
Select
u.UserID,
e.EventID,
Sum(dbo.MinutesOverlap(e.eventStart, e.eventEnd, a.availStart, a.availEnd))
From
Event e
Cross Join
User u
Left Outer Join
Available a
On u.UserID = a.UserID
Group By
u.UserID,
e.EventID
Upvotes: 1