我尝试使用MS SQL Server 2005实现以下目标,但不知道该怎么做。
目标是仅选择与锚记录不在同一时间段内开始的记录。
具有相同ID的行是一个组,并作为该组的一部分进行评估。
从基于StartDate的最早日期(A)开始,与具有相同ID的下一行(B)进行比较。
如果B在A中开始,则将B标记为无效。继续将A与具有相同ID的所有剩余记录进行比较。将A中的任何一个开头标记为无效。
将与A不重叠的下一条记录标记为有效。现在重复上述相同的过程(即检查是否有任何后续记录在新的有效记录的时间范围内开始)。
重复此过程,直到分析完所有记录。
示例:创建下表。
if object_id ('tempdb..#Dates') is not null drop table #Dates
create table #Dates (ID int, StartDate datetime, EndDate datetime)
Insert into #Dates
Select 1, '7/23/2003' , '8/22/2003' union all
select 1, '8/21/2003' , '11/19/2003' union all
select 1, '11/18/2003' , '12/18/2003' union all
select 1, '12/17/2003' , '1/16/2004' union all
select 1, '1/15/2004' , '2/14/2004' union all
select 1, '2/11/2004' , '2/26/2004' union all
select 1, '9/14/2004' , '10/14/2004' union all
select 1, '10/5/2004' , '10/20/2004' union all
select 1, '11/20/2004' , '12/20/2004' union all
select 1, '12/19/2004' , '1/18/2005' union all
select 1, '1/12/2005' , '1/27/2005' union all
select 1, '2/27/2005' , '3/11/2005'
应用重叠逻辑规则后的预期输出:
ID StartDate EndDate Valid -- --------- --------- ----- 1 7/23/2003 8/22/2003 1 1 8/21/2003 11/19/2003 0 1 11/18/2003 12/18/2003 1 1 12/17/2003 1/16/2004 0 1 1/15/2004 2/14/2004 1 1 2/11/2004 2/26/2004 0 1 9/14/2004 10/14/2004 1 1 10/5/2004 10/20/2004 0 1 11/20/2004 12/20/2004 1 1 12/19/2004 1/18/2005 0 1 1/12/2005 1/27/2005 1 1 2/27/2005 3/11/2005 1
答案 0 :(得分:0)
我想出了如何回答我自己的问题。使用row_number对记录进行排序后使用递归SQL。
if object_id ('tempdb..#Dates') is not null drop table #Dates
create table #Dates (ID int, StartDate datetime, EndDate datetime)
Insert into #Dates
Select 1, '7/23/2003' , '8/22/2003' union all
select 1, '8/21/2003' , '11/19/2003' union all
select 1, '11/18/2003' , '12/18/2003' union all
select 1, '12/19/2004' , '1/18/2005' union all
select 1, '1/12/2005' , '1/27/2005' union all
select 1, '2/27/2005' , '3/11/2005' union all
select 1, '12/17/2003' , '1/16/2004' union all
select 1, '1/15/2004' , '2/14/2004' union all
select 1, '2/11/2004' , '2/26/2004' union all
select 1, '9/14/2004' , '10/14/2004' union all
select 1, '10/5/2004' , '10/20/2004' union all
select 1, '11/20/2004' , '12/20/2004'
--Phase 1: Apply ordering to dates
if object_id ('tempdb..#OrderedRecords') is not null drop table #OrderedRecords
select *, N = row_number () over (partition by ID order by StartDate asc, EndDate desc)
into #OrderedRecords
from #Dates
--Phase 2: Apply Overlap Rules (Subsume records that overlap)
;with Subsume (ID, N, StartDate, EndDate, IntermediateStartDate, IntermediateEndDate, Valid) as
(
select ID, N, StartDate, EndDate, IntermediateStartDate = StartDate, IntermediateEndDate = EndDate,
Valid = 1
from #OrderedRecords
where N = 1
UNION ALL
select c.ID, c.N, y.StartDate, y.EndDate,
IntermediateStartDate = case when c.StartDate between y.IntermediateStartDate and y.IntermediateEndDate then y.IntermediateStartDate else c.StartDate end,
IntermediateEndDate = case when c.StartDate between y.IntermediateStartDate and y.IntermediateEndDate then y.IntermediateEndDate else c.EndDate end,
Valid = case when (c.StartDate between y.IntermediateStartDate and y.IntermediateEndDate) then 0 else 1 end
from #OrderedRecords c
join Subsume y
on y.ID = c.ID
and y.N = c.n - 1
and y.IntermediateStartDate >= c.EndDate
UNION ALL
select c.ID, c.N, c.StartDate, c.EndDate,
IntermediateStartDate = case when c.StartDate between y.IntermediateStartDate and y.IntermediateEndDate then y.IntermediateStartDate else c.StartDate end,
IntermediateEndDate = case when c.StartDate between y.IntermediateStartDate and y.IntermediateEndDate then y.IntermediateEndDate else c.EndDate end,
Valid = case when (c.StartDate between y.IntermediateStartDate and y.IntermediateEndDate) then 0 else 1 end
from #OrderedRecords c
join Subsume y
on y.ID = c.ID
and y.N = c.n - 1
and y.IntermediateStartDate < c.EndDate
)
Select ID, StartDate, EndDate, Valid
from Subsume
OPTION (MAXRECURSION 0)