2012-06-19 303 views
-1

我第一次发帖。选择范围内的最大日期,排除其他多个日期范围

我有一个棘手的任务,即查找范围内的最新日期,但不包括多个其他日期范围。我有代码确实工作,但它似乎非常重要。我在MAX(日期)范围内选择。但是,我有一个表格,其中每个节目都有其自己的日期范围(存储为DateStartDateEnd)。所以我需要MAX(日期)范围内的在该日期显示(可能有0到99显示重叠我的日期范围)。

注:我有dbo.fnSeqDates伟大的工程(通过谷歌找到),并返回一个范围内的所有日期 - 使得在12年6月1日非常快充,12年6月2日,6/3 /12...6/30/12等

我在做什么(下面)是创建一个表中的所有日期(范围内),然后找到所有在该范围内的显示(# ShowIDs)并遍历这些节目,一次一个,删除所有这些日期(从#DateRange)。最终,#DateRange只剩下“空”日期。因此,剩余在#DateRange中的MAX(日期)是我没有演出的月份中的最后一个日期。

再次,我的代码以下确实工作,但有一个更好的方法。思考?

谢谢 托德

 

CREATE procedure spLastEmptyDate 
    @DateStart date 
    , @DateEnd date 
as 
begin 

    -- VARS... 
    declare @ShowID int 
    declare @EmptyDate date 

    -- TEMP TABLE... 
    create table #DateRange(dDate date) 
    create table #ShowIDs(ShowID int) 

    -- LOAD ALL DATES IN RANGE (THIS MONTH-ISH)... 
    insert into #DateRange(dDate) 
    select SeqDate 
    from dbo.fnSeqDates(@DateStart, @DateEnd) 

    -- LOAD ALL SHOW IDs IN RANGE (THIS MONTH-IS)... 
    insert into #ShowIDs(ShowID) 
    select s.ShowID 
    from bfShow s 
    where s.DateStart = @DateStart 

    -- PRIME SHOW ID... 
    set @ShowID = 0 
    select @ShowID = min(ShowID) 
    from #ShowIDs 

    -- RUN THRU ALL, REMOVING DATES AS WE GO... 
    while (@ShowID > 0) 
    begin 
     -- REMOVE FROM TEMP... 
     delete DR 
     from #DateRange DR 
     , bfShow s 
     where DR.dDate between s.DateStart and s.DateEnd 
     and s.ShowID = @ShowID 

     -- DROP THAT ONE FROM TEMP... 
     delete from #ShowIDs 
     where ShowID = @ShowID 

     -- GET NEXT ID... 
     set @ShowID = 0 
     select @ShowID = min(ShowID) 
     from #ShowIDs 
    end 

    -- GET LAST EMPTY SPOT... 
    select @EmptyDate = max(dDate) 
    from #DateRange 

    -- CLEAN UP... 
    drop table #DateRange 
    drop table #ShowIDs 

    -- RETURN DATA... 
    select @EmptyDate as LastEmptyDateInRange 

end 
+0

我认为这是SQL Server 2008或更高版本(给定'date'数据类型)?另外,看起来所有的节目都是在同一天开始的(因为你选择了's.DateStart = @ DateStart') - 那是正确的吗?一些工作示例(S)也将有所帮助... –

回答

0

让我们知道你在,因为这将有助于确定你的选择是什么版本的SQL Server,但你应该能够之间的连接使用BETWEEN运算该fnSeqDates功能(这是一个表值函数,那么你可以加入到它,而不是直接将它们插入到一个临时表)和bfShow表:

SELECT TOP 1 tDate.SeqDate 
FROM dbo.fnSeqDates('6/1/2012', '6/30/2012') tDate 
    LEFT JOIN bfShow tShow 
     ON tDate.SeqDate BETWEEN tShow.DateStart AND tShow.DateEnd 
WHERE tShow.ShowID IS NULL -- no matches found 
ORDER BY tDate.SeqDate DESC -- to pull the most recent date 
+0

太棒了。简短而又甜美,直观。万分感谢! –

+0

PS:SQL Server 2008. –

+0

不客气! –

0

好吧,我想我会重新短语问题,并尝试揭露一些边缘案例。我没有使用你的功能。如果这是不对的,你能否举一个例子来证明它失败了?

create table bfShow (
    DateStart date, 
    DateEnd date 
) 
go 
CREATE procedure spLastEmptyDate 
    @DateStart date 
    , @DateEnd date 
as 
    --Return @DateEnd, or, if that is within a show, find the contiguous 
    --region of shows covering it, and select the day before that 
    ;with ShowsCovering as (
     select DateStart,DateEnd from bfShow where DateStart <= @DateEnd and DateEnd >= @DateEnd 
     union all 
     select s1.DateStart,s2.DateEnd 
     from 
      bfShow s1 
       inner join 
      ShowsCovering s2 
       on 
        s1.DateStart < s2.DateStart and 
        (
         --This join would be helped by an indexed computed column on bfShow, either Start-1 or End+1 
         s1.DateEnd >= s2.DateStart or 
         s1.DateEnd = DATEADD(day,-1,s2.DateStart) 
        ) 
     where 
      s2.DateStart > @DateStart 
    ), Earliest as (
     select MIN(DateStart) as MinDate from ShowsCovering 
    ) 
    --1) If there are no rows, the answer is @DateEnd 
    --2) If there are rows, and the MIN(DateStart) = @DateStart, then no day exists 
    --3) Otherwise, the answer is MIN(DateStart)-1 
    , Answer as (
     select @DateEnd as Result where exists(select * from Earliest where MinDate is null) 
     union all 
     select DATEADD(day,-1,MinDate) from Earliest where MinDate > @DateStart 
    ) 
    select Result from Answer 
go 
insert into bfShow(DateStart,DateEnd) 
values ('20120601','20120612'), 
('20120619','20120630') 
go 
exec spLastEmptyDate '20120601','20120625' 
--Result = 2012-06-18 
go 
exec spLastEmptyDate '20120525','20120625' 
--Result = 2012-06-18 
go 
exec spLastEmptyDate '20120601','20120705' 
--Result = 2012-07-05 
go 
insert into bfShow(DateStart,DateEnd) 
values ('20120613','20120618') 
go 
exec spLastEmptyDate '20120601','20120625' 
--Result - no rows 

顺便说一句,在当前的解决方案,这些行:

drop table #DateRange 
drop table #ShowIDs 

是不必要的。存储过程中创建的临时表将在存储过程退出时自动删除。所以如果你想继续使用你的解决方案,你可以避免在最后的小舞蹈,并使最后一行只是select max(dDate) as LastEmptyDateInRange from #DateRange

+0

Damien谢谢你让我知道关于#tables的消息 - 我从现在开始放下这一行。 –

+0

请注意,当您开发proc时,它可能会咬你:它们会一直保持到连接关闭,所以如果你的代码错误,并且你修复/重新运行,那个临时表可能仍然存在并给你一个错误。微不足道,但会变得烦人。 –