2017-06-02 3 views
1

enter image description hereWie Datumsbereich erhalten, die ein Kriterium

I unter Verwendung der gewünschten Ausgabe erhalten kann, wird passend while-Schleife, aber da Original-Tabelle Tausende von Rekord hat, Leistung ist sehr langsam.

Wie kann ich die gewünschten Ergebnisse mithilfe von Common Table Expression erhalten?

Vielen Dank.

+0

Welche Version von SQL Server? – Shawn

+0

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

Antwort

1

Dies führt zu den gewünschten Ergebnissen. Nicht so elegant wie Gordon, aber es lässt Lücken in Daten und Doppeltermine zu.

Wenn Sie eine Kalender-/Tally-Tabelle haben, kann die Cte-Logik entfernt werden.

Beispiel

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) 

Returns

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

Danke John für Ihre Hilfe. – Ram

+1

@Ram Glücklich zu helfen. –

1

Dies ist eine Variante des Lücken-und-Inseln-Problems. In diesem Fall können Sie Datumsberechnungen verwenden, um die Zeilen mit benachbarten Daten zu berechnen:

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; 

Hinweis: Dies setzt voraus, dass die Daten zusammenhängend sind und haben keine Duplikate. Die Abfrage kann geändert werden, um diese Faktoren zu berücksichtigen.

Die Grundidee ist, dass wenn Sie eine Folge von Tagen haben, die einzeln nacheinander zunehmen, können Sie eine Folge von Werten subtrahieren und eine Konstante erhalten. Das ist, was grp ist. Der Rest ist nur Aggregation.

Verwandte Themen