我的第一次发帖。
我有一个棘手的任务,即在一个范围内找到最新日期,但排除多个其他日期范围。我有确实有效的代码,但它看起来非常费力。
我在一个范围内选择 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
答案 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
。