Dav*_*vid 8 sql t-sql algorithm sql-server-2005 linq-to-sql
我遇到了一个更大问题的路障.
作为大型查询的一部分,我需要解决"守夜人"问题.我有一张表,其中包括日程安排班次:
ID | Start | End
1 | 2009-1-1 06:00 | 2009-1-1 14:00
2 | 2009-1-1 10:00 | 2009-1-1 18:00
3 | 2009-2-1 20:00 | 2009-2-2 04:00
4 | 2009-2-2 06:00 | 2009-2-2 14:00
Run Code Online (Sandbox Code Playgroud)
作为查询的一部分,我需要确定在给定时间范围内房间内是否至少有一名守望者.
因此,如果我将范围指定2009-1-1 06:00为2009-1-1 12:00,则结果为真,因为第1和第2轮合并以涵盖此时间段 - 实际上可以链接任意数量的轮班以保持监视.但是,如果我检查2009-2-1 22:00过2009-1-2 10:00,结果是错误的,因为第二天早上4点到6点之间有休息时间.
我想实现这个无论是在LINQ,或在SQL Server(2005)的用户定义的函数,在这两种情况下,这仅仅是一个必须运行来标识需要注意的元素一个大的查询逻辑的一部分.真实数据集涉及与任何给定时间段相交的大约一百个移位记录,但并不总是覆盖整个范围.
我发现的最接近的是 如何使用SQL Server 对范围值进行分组,但是它取决于在下一个范围开始之前结束的每个范围.如果我可以构建相同的手表统一视图,只考虑重叠的手表,那么检查是否涵盖了特定时间将是微不足道的.统一视图如下所示:
Start | End
2009-1-1 06:00 | 2009-1-1 18:00
2009-2-1 20:00 | 2009-2-2 04:00
2009-2-2 06:00 | 2009-2-2 14:00
Run Code Online (Sandbox Code Playgroud)
注意:通过拉动所有数据并在其上运行一些手动循环来实现整个过程相对容易,但这是当前的系统,并且由于班次的数量和必须的时间范围的数量,它相当慢被检查.
这是一种扁平化日期范围的方法
Start | End
2009-1-1 06:00 | 2009-1-1 18:00
2009-2-1 20:00 | 2009-2-2 04:00
2009-2-2 06:00 | 2009-2-2 14:00
Run Code Online (Sandbox Code Playgroud)
您必须比较每一行中的上一个 和 下一个日期,看看是否

使用上面的代码,实现 UDF 非常简单,如下所示。
create function fnThereIsWatchmenBetween(@from datetime, @to datetime)
returns bit
as
begin
declare @_Result bit
declare @FlattenedDateRange table (
Start datetime,
[End] datetime
)
insert @FlattenedDateRange(Start, [End])
select distinct
Start =
case
when Pv.Start is null then Curr.Start
when Curr.Start between Pv.Start and Pv.[End] then Pv.Start
else Curr.Start
end,
[End] =
case
when Curr.[End] between Nx.Start and Nx.[End] then Nx.[End]
else Curr.[End]
end
from shift Curr
left join shift Pv on Pv.ID = Curr.ID - 1 --; prev
left join shift Nx on Nx.ID = Curr.ID + 1 --; next
if exists( select 1
from FlattenedDateRange R
where @from between R.Start and R.[End]
and @to between R.Start and R.[End]) begin
set @_Result = 1 --; There is/are watchman/men during specified date range
end
else begin
set @_Result = 0 --; There is NO watchman
end
return @_Result
end
Run Code Online (Sandbox Code Playgroud)