2012-11-17 244 views
1

试图在SQL中为以下内容编写查询:事件具有开始/结束日期/时间。 用户可用于某些时间。我如何找到用户可用于特定事件的总时间?在另一个日期范围内总结日期范围

实施例:

--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 

用户可以自由135分钟(60分钟从15:00-16:00,16 10分钟:30-16:40,16 65分钟:55- 18:00)。

有些帮助编写SQL会非常有帮助,发现这一个棘手!

+0

@米奇小麦我可以得到事件运行,用户可用的总时间,即'SUM(DATEDIFF(MI,availStart,availEnd))',但我确实不能工作的总时间了解如何统计事件时间内的可用条目(包括稍后开始/结束但仅统计事件内部的那些条目)。 – Marcus

回答

1

现在测试了它:http://sqlfiddle.com/#!3/a4e7a/2

我假定一个用户表。性能改进的空间很大。例如通过添加一个where子句来消除不重叠的范围。如果用一个可怕的case语句替换函数,它可能也会更快。

棘手的一点是搞清楚两个时间段有多少重叠的算法。我总是发现它有用绘制的情况下的图片:

Case 1 
|------| 
     |=======| 

Case 2 
|------| 
    |======| 

Case 3 
|-------| 
    |===| 

和等效的命令相反。

原来重叠是两个结束时间的最小值减去两个开始时间的最大值。 (如果为负数则不重叠)。我总是必须检查所有的情况才能重新说服自己。

-- 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