2017-06-02 110 views
1

enter image description here如何获得其匹配标准

我可以通过使用while循环,但由于原来的表有成千上万条记录,性能非常慢获得所需的输出日期范围。

如何使用通用表达式得到期望的结果?

谢谢。

+0

的SQL Server的哪个版本? – Shawn

+0

@Shawn其Microsoft SQL Server 2008(SP4) – Ram

回答

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 
+0

谢谢John的帮助。 – Ram

+1

@Ram高兴地帮助。 –

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是。剩下的只是聚合。