2017-12-22 10 views
0

Ist es möglich, eine SQL-Abfrage zu schreiben, die Zeilen mit Start- und Enddatum in Zeilen zusammenfassen, die zusammenhängende Start haben und Enddaten?SQL Server zusammenhängende Daten - Zusammenfassen mehrerer Zeilen in zusammenhängende Start- und Enddatum Zeilen ohne CTEs, Schleifen, ... s

Die Einschränkung ist, dass es reguläre sql sein muss, d. H. Keine CTEs, Schleifen und dergleichen, da ein Drittanbieter-Tool verwendet wird, das nur eine SQL-Anweisung mit Select beginnen lässt.

z.B .:

ID  StartDate   EndDate 

1001,  Jan-1-2018,  Jan-04-2018 
1002,  Jan-5-2018,  Jan-13-2018 
1003,  Jan-14-2018,  Jan-18-2018 
1004,  Jan-25-2018,  Feb-05-2018 

Die erforderliche Ausgabe muss sein:

Jan-1-2018,  Jan-18-2018 
Jan-25-2018,  Feb-05-2018 

Danke

+0

„, ein Drittanbieter-Tool verwendet wird, dass nur eine SQL-Anweisung erlaubt Select zu starten "- Liebe diese Werkzeuge! NICHT! –

+1

Wie erstellt man eine Ansicht daraus und dann die Ansicht im Tool – Squirrel

+0

Mit welcher Version von SQL Server arbeiten Sie? Auch das ist eine großartige Idee von @Squirrel. – tarheel

Antwort

0

Sie Vorteil sowohl window functions und die Verwendung eines Begriffs gaps-and-islands genannt nehmen. In Ihrem Fall wären zusammenhängende Daten die Insel, und die Lücken sind selbsterklärend.

Ich schrieb die Antwort unten in einer ausführlichen Weise, um zu verdeutlichen, was die Abfrage tut, aber es könnte höchstwahrscheinlich auf eine andere Weise geschrieben werden, die prägnanter ist. Bitte beachten Sie meine Kommentare in der Antwort, die erklären, was jeder Schritt (Unterabfrage) tut.

--Determine Final output 
select min(c.StartDate) as StartDate 
, max(c.EndDate) as EndDate 
from (
    --Assign a number to each group of Contiguous Records 
    select b.ID 
    , b.StartDate 
    , b.EndDate 
    , b.EndDatePrev 
    , b.IslandBegin 
    , sum(b.IslandBegin) over (order by b.ID asc) as IslandNbr 
    from (
     --Determine if its Contiguous (IslandBegin = 1, means its not Contiguous with previous record) 
     select a.ID 
     , a.StartDate 
     , a.EndDate 
     , a.EndDatePrev 
     , case when a.EndDatePrev is NULL then 1 
       when datediff(d, a.EndDatePrev, a.StartDate) > 1 then 1 
       else 0 
      end as IslandBegin 
     from (
      --Determine Prev End Date 
      select tt.ID 
      , tt.StartDate 
      , tt.EndDate 
      , lag(tt.EndDate, 1, NULL) over (order by tt.ID asc) as EndDatePrev 
      from dbo.Table_Name as tt 
      ) as a 
     ) as b 
    ) as c 
group by c.IslandNbr 
order by c.IslandNbr 
+0

Vielen Dank Tarheel, das sieht sehr interessant aus! Vielen Dank für die Kommentare. Ich hatte heute einen sehr frühen Start und bin im Shutdown-Modus und werde das am Morgen versuchen, Danke nochmal. – rod

+0

@rod Wie ist das für dich gelaufen? – tarheel

1

Ich hoffe folgende SQL-Abfrage Sie Lücken und bedeckt Termine gegebenen Fall identifizieren helfen können

ich nicht einen CTE Ausdruck eines dates table function usw. Auf der anderen Seite verwendet haben, habe ich eine Zahl Tabelle mit master..spt_values ​​zum Generieren der Dattentabelle als Haupttabelle eines LINKEN Joins Sie können eine Nummerntabelle oder eine Dattentabelle erstellen, wenn sie nicht Ihren Anforderungen entspricht.

In der Abfrage, um Änderungen zwischen zu erfassen Grenzen habe ich verwendet SQL LAG() function, die enabl das Ergebnis ES mich mit früherem Wert einer Spalte in einer sortierten Liste

select 
    max(startdate) as startdate, 
    max(enddate) as enddate 
from (
    select 
     date, 
     case when exist = 1 then date else null end as startdate, 
     case when exist = 0 then dateadd(d,-1,date) else null end as enddate, 
     (row_number() over (order by date) + 1)/2 as rn 
    from (
     select date, exist, case when exist <> (lag(exist,1,'') over (order by date)) then 1 else 0 end as changed 
     from (
      select 
       d.date, 
       case when exists (select * from Periods where d.date between startdate and enddate) then 1 else 0 end as exist 
      from (
       SELECT dateadd(dd,number,'20180101') date 
       FROM master..spt_values 
       WHERE Type = 'P' and dateadd(dd,number,'20180101') <= '20180228' 
      ) d 

     ) cte 
    ) tbl 
    where changed = 1 
) dates 
group by rn 

Hier zu vergleichen ist

enter image description here

Verwandte Themen