【问题标题】:Determine available date ranges between a given start and end date确定给定开始日期和结束日期之间的可用日期范围
【发布时间】:2012-11-19 19:27:53
【问题描述】:

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

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

一个例子:

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 月 4 日的开始日期和 2012 年 12 月 10 日的结束日期。可用日期为.. 2012-11-06 至 2012-11-09、2012-11-21 至 2012-11-30、2012-12-06-2012-12-10。

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

【问题讨论】:

    标签: sql-server-2008 tsql


    【解决方案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 表达式来修剪超出请求日期的时段。

    【讨论】:

    • 哇,我已经用几个日期对此进行了测试,似乎效果很好。我也学到了一些东西。谢谢达米安。
    猜你喜欢
    • 2020-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-06
    • 1970-01-01
    • 2014-03-18
    • 2015-07-05
    相关资源
    最近更新 更多