在SQL中为每个保存的日期选择可用时间

时间:2014-06-05 05:10:25

标签: sql sql-server

我有一个系统,用户可以在该系统中预订不同日期和时间段的房间,在数据库中我们将保存bookingdateStartTimeEndTime,如下表所示,startimeendtime之间的最小间隔为30分钟。

MeetingDate -> Date (values like '6/4/2014','6/5/2014')
StartTime -> Time (values like '10:00:00', '11:00:00')
EndTime -> Time (values like '13:00:00', '14:00:00')

我需要定期检查所有日期的可用时间段,考虑到08:00 AM - 06:00 PM的时间限制,因为我创建了下面的cte表,它将列出所有时间段间隔30分钟

现在我想通过过滤来过滤每个日期的可用时间 通过将其与创建的'TimeSlots' ste表匹配来预订时间 以上,或任何其他方法也可以

如果有任何需要进一步的信息请告诉我

1 个答案:

答案 0 :(得分:1)

试试这个(原始输出):

create table Bookings (MeetingDate date, StartTime time, EndTime time);

insert into Bookings (MeetingDate, StartTime, EndTime) values
('2014-05-01', '9:15', '12:15'),
('2014-05-02', '8:00', '10:00'),
('2014-05-02', '10:30', '11:00'),
('2014-05-02', '11:00', '17:00'),
('2014-05-03', '09:00', '18:00');

with [times_between_0800_and_1800] as 
(
    select cast('08:00' as time) [time]
    union all
    select dateadd(minute, 10, [time])
    from [times_between_0800_and_1800]
    where [time] < '18:00'
)
,[distinct_dates] as
(
    select distinct MeetingDate [date] from Bookings
)
,[dates_with_time] as
(
    select cast(d.[date] as datetime) + cast(t.[time] as datetime) [value]
    from [distinct_dates] d
    cross join [times_between_0800_and_1800] t
)
select dt.*
from [dates_with_time] dt
left join Bookings b on dt.value between cast(b.MeetingDate as datetime) + cast(b.StartTime as datetime) and cast(b.MeetingDate as datetime) + cast(b.EndTime as datetime)
where b.MeetingDate is null
order by dt.value

U P D A T E

另一个更复杂的解决方案,它返回可用的时间段(精确到10分钟)

with [times_between_0800_and_1800] as 
(
    select cast('08:00' as time) [time]
    union all
    select dateadd(minute, 10, [time])
    from [times_between_0800_and_1800]
    where [time] < '18:00'
)
,[distinct_dates] as
(
    select distinct MeetingDate [date] from Bookings
)
,[dates_with_time] as
(
    select cast(d.[date] as datetime) + cast(t.[time] as datetime) [value]
    from [distinct_dates] d
    cross join [times_between_0800_and_1800] t
)
,[raw_available_times] as
(
    select dt.value, cast(dt.value as date) [date]
    from [dates_with_time] dt
    left join Bookings b on dt.value between cast(b.MeetingDate as datetime) + cast(b.StartTime as datetime) and cast(b.MeetingDate as datetime) + cast(b.EndTime as datetime)
    where b.MeetingDate is null
)
,[ranked] as
(
    select [value]
    , [date]
    , rank() over(partition by [date] order by [value]) [rank]
    from [raw_available_times]
)
,[islands] as
(
    select r1.value, r1.[date], r1.[rank]
    , r2.value [r2_value]
    , rank() over(partition by case when r2.value is null then 1 else 0 end order by r1.value) [order]
    from [ranked] r1
    left join [ranked] r2 on r1.[date] = r2.[date]
        and r1.[rank] = r2.[rank] + 1
        and datediff(minute, r2.[value], r1.[value]) = 10
)
select i1.[date], i1.[value] [startdate]
, isnull(_max.value, _last.value) [enddate] 
from [islands] i1
left join [islands] i2 on i1.[order] + 1 = i2.[order]
    and i2.[r2_value] is null
outer apply (
    select max(value) [value]
    from [islands]
    where value > i1.[value]
    and value < i2.[value]) as _max
outer apply (
    select max(value) [value]
    from [islands]) as _last
where i1.[r2_value] is null;

Check SQL Fiddle