如何获取符合条件的日期范围

时间:2017-06-02 19:44:05

标签: sql sql-server

enter image description here

我可以通过使用while循环获得所需的输出,但由于原始表有数千条记录,因此性能非常慢。

如何使用Common Table Expression获得所需的结果?

谢谢。

2 个答案:

答案 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