T-SQL 日期时间问题。
我有一组时间范围。在这些时间范围内,可能会有一组重叠的时间范围,我称之为“阻塞”时间。被封锁的时间不会超过一天。我想要做的是分割时间以排除被封锁的时间,基本上给我未被“封锁”的时间范围。可以安全地假设阻塞时间不能落在时间范围之外。
示例:我从上午 9 点工作到下午 5 点,下午 1 点有 30 分钟的午休时间。我想要 2 行的结果:上午 9 点到下午 1 点和下午 1.30 到下午 5 点。
如前所述,我有一组时间范围,因此在上面的示例中,每天的工作时间可能不同,休息的次数和持续时间也可能不同。
我想在 SQL 方面,输入参数应该是这样的:
declare @timeranges table ( StartDateTime datetime, EndDateTime datetime )
declare @blockedtimes table ( StartDateTime datetime, EndDateTime datetime )
insert into @timeranges
select '01 Jan 2009 09:00:00', '01 Jan 2009 17:00:00'
union select '02 Feb 2009 10:00:00', '02 Feb 2009 13:00:00'
insert into @blockedtimes
select '01 Jan 2009 13:00:00', '01 Jan 2009 13:30:00'
union select '02 Feb 2009 10:30:00', '02 Feb 2009 11:00:00'
union select '02 Feb 2009 12:00:00', '02 Feb 2009 12:30:00'
结果集看起来像这样。
Start End
--------------------- ---------------------
'01 Jan 2009 09:00:00' '01 Jan 2009 13:00:00'
'01 Jan 2009 13:30:00' '01 Jan 2009 17:00:00'
'02 Feb 2009 10:00:00' '02 Feb 2009 10:30:00'
'02 Feb 2009 11:00:00' '02 Feb 2009 12:00:00'
'02 Feb 2009 12:30:00' '02 Feb 2009 13:00:00'
我可以用游标或 while 循环来做到这一点,但如果有人可以建议如何在没有迭代的情况下做到这一点,那就太好了 - 谢谢。
最佳答案
第一次剪辑,可能会有一些问题,但我会继续努力。
适用于给定的数据,只需要尝试其他场景
declare @timeranges table ( StartDateTime datetime, EndDateTime datetime )
declare @blockedtimes table ( StartDateTime datetime, EndDateTime datetime )
insert into @timeranges
select '01 Jan 2009 09:00:00', '01 Jan 2009 17:00:00'
union select '02 Feb 2009 10:00:00', '02 Feb 2009 13:00:00'
--union select '03 Feb 2009 10:00:00', '03 Feb 2009 15:00:00'
insert into @blockedtimes
select '01 Jan 2009 13:00:00', '01 Jan 2009 13:30:00'
union select '02 Feb 2009 10:30:00', '02 Feb 2009 11:00:00'
union select '02 Feb 2009 12:00:00', '02 Feb 2009 12:30:00'
--build an ordered, time range table with an indicator
--to determine which ranges are timeranges 'tr'
--and which are blockedtimes 'bt'
--
declare @alltimes table (row int, rangetype varchar(10), StartDateTime datetime, EndDateTime datetime )
insert into @alltimes
select
row_number() over (order by a.startdatetime), *
from
(
select 'tr' as rangetype ,startdatetime, enddatetime from @timeranges
union
select 'bt' as rangetype ,startdatetime, enddatetime from @blockedtimes
)a
--what does the data look like
--
select * from @alltimes
--
-- build up the results
select
--start time is either the start time of a timerange, or the end of a blockedtime
case
when at1.rangetype = 'tr' then at1.startdatetime
when at1.rangetype = 'bt' then at1.enddatetime
end as [Start],
case
--a time range followed by another time range : end time from the current time range
when at1.rangetype = 'tr' and (select at2.rangetype from @alltimes at2 where at2.row = at1.row+1) = 'tr'
then at1.enddatetime
--a time range followed by nothing (last record) : end time from the currenttime range
when at1.rangetype = 'tr' and (select at2.rangetype from @alltimes at2 where at2.row = at1.row+1) is null
then at1.enddatetime
--a time range followed by a blockedtime : end time is start time of blocked time
when at1.rangetype = 'tr' and (select at2.rangetype from @alltimes at2 where at2.row = at1.row+1) = 'bt'
then (select top 1 at2.startdatetime from @alltimes at2 where at2.row > at1.row and at2.rangetype = 'bt' order by row)
--a blocked time followed by a blockedtime : end time is start time of next blocked time
when at1.rangetype = 'bt' and (select at2.rangetype from @alltimes at2 where at2.row = at1.row+1) = 'bt'
then (select top 1 at2.startdatetime from @alltimes at2 where at2.row > at1.row and at2.rangetype = 'bt' order by row)
--a blocked time followed by a time range : end time is end time of previous time range
when at1.rangetype = 'bt' and (select at2.rangetype from @alltimes at2 where at2.row = at1.row+1) = 'tr'
then (select top 1 at2.enddatetime from @alltimes at2 where at2.row < at1.row and at2.rangetype = 'tr' order by row desc)
--a blocked time followed by nothing (last record) : end time is end time of previous time range
when at1.rangetype = 'bt' and (select at2.rangetype from @alltimes at2 where at2.row = at1.row+1) is null
then (select top 1 at2.enddatetime from @alltimes at2 where at2.row < at1.row and at2.rangetype = 'tr' order by row desc)
end as [End]
from @alltimes at1
关于sql - 选择重叠的时间范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1271825/