答案 0 :(得分:1)
这是间隙和岛屿问题的变体。在这种情况下,您可以使用日期算术来计算具有相邻日期的行:
select securityId, isheld, min(asofdate), max(asofdate)
from (select t.*,
datediff(day,
- row_number() over (partition by securityId, isheld
order by asofdate
),
asofdate) as grp
from t
) t
group by grp, securityId, isheld;
注意:这假定日期是连续的并且没有重复。可以修改查询以考虑这些因素。
基本思想是,如果你有一个一天增加一个天的序列,那么你可以减去一系列值并得到一个常数。那就是grp
。其余的只是聚合。
答案 1 :(得分:1)
这将产生预期的结果。不像戈登那样优雅,但它确实允许日期和重复日期的差距。
如果您有日历/帐单表,则可以删除cte逻辑。
示例强>
Declare @YourTable Table ([AsOfDate] Date,[SecurityID] varchar(50),[IsHeld] bit)
Insert Into @YourTable Values
('2017-05-19','S1',1)
,('2017-05-20','S1',1)
,('2017-05-21','S1',1)
,('2017-05-22','S1',1)
,('2017-05-23','S1',0)
,('2017-05-24','S1',0)
,('2017-05-25','S1',0)
,('2017-05-26','S1',1)
,('2017-05-27','S1',1)
,('2017-05-28','S1',1)
,('2017-05-29','S1',0)
,('2017-05-30','S1',0)
,('2017-05-31','S1',1)
;with cte1 as ( Select D1=min(AsOfDate),D2=max(AsOfDate) From @YourTable )
,cte2 as (
Select Top (DateDiff(DAY,(Select D1 from cte1),(Select D2 from cte1))+1)
D=DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),(Select D1 from cte1))
,R=Row_Number() over (Order By (Select Null))
From master..spt_values n1,master..spt_values n2
)
Select [SecurityID]
,[StartDate] = min(D)
,[EndDate] = max(D)
From (
Select *,Grp = dense_rank() over (partition by securityId order by asofdate )-R
From @YourTable A
Join cte2 B on AsOfDate=B.D
Where IsHeld=1
) A
Group By [SecurityID],Grp
Order By min(D)
<强>返回强>
SecurityID StartDate EndDate
S1 2017-05-19 2017-05-22
S1 2017-05-26 2017-05-28
S1 2017-05-31 2017-05-31