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 分钟(15:00-16:00 60 分钟,16:30-16:40 10 分钟,16:55-18:00 65 分钟)。

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

4

1 回答 1

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
于 2012-11-17T02:20:15.867 回答