俱乐部在SQL Server中重叠时隙

时间:2011-12-03 17:26:38

标签: sql sql-server sql-server-2005 sql-server-2008

我有一张表,其中包含重叠时段的记录。

例如:日历(Id int,StartDate datetime,EndDate datetime,EventTitle nvarchar(100),...)

记录就像

  
      
  1. 01/20/2011 08:15 AM --- 01/20/2011 08:40 AM
  2.   
  3. 01/20/2011 08:20 AM --- 01/20/2011 08:55 AM
  4.   
  5. 01/20/2011 12:30 PM --- 01/20/2011 01:15 PM
  6.   
  7. 01/20/2011 02:00 PM --- 01/20/2011 02:45 PM
  8.   
  9. 01/20/2011 02:15 PM --- 01/20/2011 02:30 PM
  10.   
  11. 01/21/2011 12:30 PM --- 01/21/2011 01:15 PM
  12.   
  13. .......
  14.   
  15. .......
  16.   

该表代表一个人的活动时间表

我想把重叠的插槽聚集在一起给出:

  
      
  1. 01/20/2011 08:15 AM --- 01/20/2011 08:55 AM
  2.   
  3. 01/20/2011 12:30 PM --- 01/20/2011 01:15 PM
  4.   
  5. 01/20/2011 02:00 PM --- 01/20/2011 02:45 PM
  6.   
  7. 01/21/2011 12:30 PM --- 01/21/2011 01:15 PM
  8.   
  9. ...
  10.   
  11. ...
  12.   

我遇到问题的这一部分...(我删除了我粘贴在这里的代码,因为它看起来很糟糕。我第一次使用stackoverflow。)

我的部分实际要求是在两个给定日期之间找到一个时间段[t](比方说25分钟),我可以将其纳入时间表。 [t]必须在任何一天的上午8:00到下午05:00之间找到。

1 个答案:

答案 0 :(得分:2)

这是一个有趣的问题。

对于指定日期,我们可以考虑重叠(我输入了您的所有日期时间,但是对于2011年1月1日):

SELECT        dt1.StartTime AS StartOverlap,
              CASE 
                WHEN dt1.EndTime > dt2.EndTime THEN dt1.EndTime
                ELSE dt2.EndTime
              END AS EndOverlap
FROM          datetimetest dt1, datetimetest dt2
WHERE         dt2.StartTime > dt1.StartTime
AND           dt2.StartTime < dt1.EndTime

这给了我:

StartOverlap        EndOverlap
01/01/2011 08:15:00 01/01/2011 08:55:00
01/01/2011 14:00:00 01/01/2011 14:45:00

太好了,我们现在知道我们不能使用这种重叠的开始和结束时间。

我们如何得到其他没有重叠的时间?

我会查看重叠范围内的所有时间段,然后选择不在该日期范围内的ID:

SELECT id 
FROM (SELECT        dt1.StartTime AS StartOverlap,
                CASE 
                  WHEN dt1.EndTime > dt2.EndTime THEN dt1.EndTime
                  ELSE dt2.EndTime
                END AS EndOverlap
  FROM          datetimetest dt1, datetimetest dt2
  WHERE dt2.StartTime > dt1.StartTime
  AND dt2.StartTime < dt1.EndTime
 ) AS Overlaps, datetimetest dtt

WHERE dtt.StartTime >= Overlaps.StartOverlap 
AND dtt.EndTime <= Overlaps.EndOverlap

这为我提供了重叠中所有ID的列表。然后我只选择不在重叠中的所有条目:

SELECT StartTime, EndTime FROM datetimetest
WHERE id NOT IN(
SELECT id 
FROM (SELECT        dt1.StartTime AS StartOverlap,
                CASE 
                  WHEN dt1.EndTime > dt2.EndTime THEN dt1.EndTime
                  ELSE dt2.EndTime
                END AS EndOverlap
  FROM          datetimetest dt1, datetimetest dt2
  WHERE dt2.StartTime > dt1.StartTime
  AND dt2.StartTime < dt1.EndTime
 ) AS Overlaps, datetimetest dtt

WHERE dtt.StartTime >= Overlaps.StartOverlap 
AND dtt.EndTime <= Overlaps.EndOverlap)

给我:

StartTime           EndTime
01/01/2011 12:30:00 01/01/2011 13:15:00

然后,我可以将两个查询合并在一起,为我提供所有使用时间段的列表。

由于我们实际上正在交叉加入同一个表,因此我会在每个查询中添加一个附加子句,以将日期约束为单个日期。