2012-06-19 204 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時,它可能會咬你:它們會一直保持到連接關閉,所以如果你的代碼錯誤,並且你修復/重新運行,那個臨時表可能仍然存在並給你一個錯誤。微不足道,但會變得煩人。 –