确定给定开始日期和结束日期之间的可用日期范围

时间:2012-11-19 11:01:14

标签: sql-server-2008 tsql

背景(非常简化): 我有一个横幅空间,我在网站上出售。可以为给定的开始和结束日期预订横幅,此横幅不能重复预订。横幅可以在一年内多次预订,但在同一天不得超过一次。

我的问题: 保存预订时,用户输入开始/结束日期,现在可以在此开始/结束日期内多次预订横幅,我想自动预订开始/结束日期内的任何免费日期。

一个例子:

s|aaaaaaa|s1------e1|aaaaaaaaa|s2------e2|aaaaaa|e

s / e =用户输入的预订日期。 s1 - e1 =首次预订。 s2 - e2 =第二次预订。 aaa .. =可用日期范围。

在tsql中我想计算aaa的开始/结束日期..(可用日期范围)。然后将它们插入预订表。

预订表如下:

BookingId------BannerId-----StartDate-----ExpiryDate
000000001------00000001-----2012-11-01----2012-11-05
000000002------00000001-----2012-11-10----2012-11-15
000000003------00000001-----2012-11-16----2012-11-20
000000004------00000001-----2012-12-01----2012-12-05

因此,如果用户输入的开始日期为2012-11-04,结束日期为2012-12-10。可用日期为.. 2012-11-06至2012-11-09,2012-11-21至2012-11-30,2012-12-06-2012-12-10。

感谢您提供有关如何执行此操作的任何建议。

1 个答案:

答案 0 :(得分:1)

这似乎可以解决问题:

(所有一个脚本,但拆分以便您可以看到每个部分)数据设置:

declare @Bookings table (
BookingId char(9) not null,
BannerId char(8) not null,
StartDate date not null,
ExpiryDate date not null
)
insert into @Bookings (BookingId,BannerId,StartDate,ExpiryDate) values
('000000001','00000001','20121101','20121105'),
('000000002','00000001','20121110','20121115'),
('000000003','00000001','20121116','20121120'),
('000000004','00000001','20121201','20121205')

输入:

declare @StartDate date
declare @EndDate date
select @StartDate = '20121104',@EndDate = '20121210'

查询:

;With Ordered as (
    select *,ROW_NUMBER() OVER (PARTITION BY BannerID ORDER BY StartDate) as rn
    from @Bookings
), FreePeriods as (
    select
        o1.BannerId,
        DATEADD(day,1,o1.ExpiryDate) as StartDate,
        DATEADD(day,-1,o2.StartDate) as EndDate
    from
        Ordered o1
            inner join
        Ordered o2
            on
                o1.BannerId = o2.BannerId and
                o1.rn = o2.rn - 1
    where
        DATEDIFF(day,o1.ExpiryDate,o2.StartDate) >= 3
    union all
    select
        BannerId,'00010101',DATEADD(day,-1,MIN(StartDate)) from @Bookings group by BannerID
    union all
    select
        BannerID,DATEADD(day,1,MAX(ExpiryDate)),'99991231' from @Bookings group by BannerID
)
select
    BannerID,
    CASE WHEN @StartDate > StartDate then @StartDate ELSE StartDate END as StartDate,
    CASE WHEN @EndDate < EndDate then @EndDate ELSE EndDate END as EndDate
from
    FreePeriods fp
where
    fp.EndDate >= @StartDate and
    fp.StartDate <= @EndDate

基本上,我将预订的日期组织成连续的对,然后使用每对构建它们之间存在的自由时间段。我还伪造了两个时期 - 一个从最开始预订到最早预订,一个从最新预订到结束时间。

然后,在最后一个查询中,查找与请求日期重叠的句点,并使用一些CASE表达式来修剪超出请求日期的句点。