开发者

Find overlapping time ranges

I'm surprised this hasn't come up yet.

In T-SQL, I need to find the intervals (defined by startDateTime and endDateTime) that overlap with daily interval (say 9am-5pm).

For example, with table:

CREATE TABLE [dbo].[Interval](
    [startDateTime] [datetime] NOT NULL,
    [endDateTime] [datetime] NOT NULL
)

Solution would be the procedure that returns only overlapping intervals:

CREATE PROCEDURE FindIntervals
    -- Add the parameters for the stored procedure here
    @from varchar(5) = '9:00', 
    @to varchar(5) = '17:00'
AS
BEGIN
    select * from Interval
    where ...
END
GO

EDIT: Example intervals:

  1. Sep 7 2011 8:00 AM - Sep 7 2011 8:30 PM
  2. Sep 7 2011 11:00 AM - Sep 7 2011 1:00 PM
  3. Sep 7 2011 1:00 PM - Sep 7 2011 6:00 PM
  4. Sep 9 2011 8:00 AM - Sep 9 2011 8:30 PM
  5. Sep 9 2011 11:00 AM - Sep 9 2011 1:00 PM
  6. Sep 9 2011 1:00 PM - Sep 9 2011 6:00 PM

So, for given interval "nine to five", 2, 3, 5 and 6 should be returned, as they overl开发者_C百科ap the given input.

But,

  1. Sep 9 2011 8:00 AM - Sep 10 2011 8:30 PM

also fits, because it includes entire day.

Please, I need help with matching string and datetime values in T-SQL, not abstract "less then"/"greater then" solutions.


declare @Interval table
(
  startDateTime datetime,
  endDateTime datetime
)

insert into @Interval values
('2011-09-07T08:00:00', '2011-09-07T08:30:00'),
('2011-09-07T11:00:00', '2011-09-07T13:00:00'),
('2011-09-07T13:00:00', '2011-09-07T18:00:00'),
('2011-09-09T08:00:00', '2011-09-09T08:30:00'),
('2011-09-09T11:00:00', '2011-09-09T13:00:00'),
('2011-09-09T13:00:00', '2011-09-09T18:00:00'),
('2011-09-09T08:00:00', '2011-09-10T08:30:00')

declare @from varchar(5) = '09:00'
declare @to varchar(5) = '17:00'

;with L(MinDate, MaxDate) as
(
  select dateadd(day, datediff(day, 0, min(startDateTime)), 0),
         dateadd(day, datediff(day, 0, max(endDateTime)), 0)
  from @Interval
), 
D(fromTime, endTime) as
(
  select dateadd(day, Number.number, L.MinDate)+cast(@from as datetime),
         dateadd(day, Number.number, L.MinDate)+cast(@to as datetime)
  from L
    inner join master..spt_values as Number
      on Number.number <= datediff(day, L.MinDate, L.MaxDate)
  where Number.type = 'P'
)
select I.startDateTime,
       I.endDateTime
from @Interval as I
where exists (select *
              from D
              where I.startDateTime < D.endTime and
                    I.endDateTime > D.fromTime)

Result:

startDateTime           endDateTime
----------------------- -----------------------
2011-09-07 11:00:00.000 2011-09-07 13:00:00.000
2011-09-07 13:00:00.000 2011-09-07 18:00:00.000
2011-09-09 11:00:00.000 2011-09-09 13:00:00.000
2011-09-09 13:00:00.000 2011-09-09 18:00:00.000
2011-09-09 08:00:00.000 2011-09-10 08:30:00.000

If you expect to have a date range of more than 2048 days you need to replace master..spt_values with a numbers table. Make sure the numbers table starts with 0.

SQL Server 2008 version

;with L(MinDate, MaxDate) as
(
  select cast(min(startDateTime) as date),
         cast(max(endDateTime) as date)
  from @Interval
), 
D(fromTime, endTime) as
(
  select dateadd(day, Number.number, L.MinDate)+cast(@from as datetime),
         dateadd(day, Number.number, L.MinDate)+cast(@to as datetime)
  from L
    inner join master..spt_values as Number
      on Number.number <= datediff(day, L.MinDate, L.MaxDate)
  where Number.type = 'P'
)
select I.startDateTime,
       I.endDateTime
from @Interval as I
where exists (select *
              from D
              where I.startDateTime < D.endTime and
                    I.endDateTime > D.fromTime)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜