选择范围内的最大日期,不包括多个其他日期范围

时间:2012-06-19 04:59:56

标签: sql sql-server asp-classic filter date-range

我的第一次发帖。

我有一个棘手的任务,即在一个范围内找到最新日期,但排除多个其他日期范围。我有确实有效的代码,但它看起来非常费力。

我在一个范围内选择 MAX(日期)。但是,我有一个表 bfShow ,其中每个节目都有自己的日期范围(存储为 DateStart DateEnd )。所以我需要在 NOT 在该日期显示的范围内的 MAX(日期)(可能有0到99显示重叠我的日期范围)。< / p>

注意:我有 dbo.fnSeqDates ,效果很好(通过Google找到)并返回范围内的所有日期 - 非常快速填写6/1 / 12,6 / 2/12 ,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

2 个答案:

答案 0 :(得分:0)

让我们知道您所使用的SQL Server版本,因为这有助于确定您的选项,但您应该能够在fnSeqDates函数之间的JOIN中使用BETWEEN运算符(它是一个表值函数,所以你可以直接加入它而不是将它们插入临时表)和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

答案 1 :(得分: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