2016-07-25 13 views
0

Dies ist eine Frage zum Feilen Bereiche von Daten. Insbesondere habe ich eine Ergebnismenge, bei der jede Zeile einen StartDate- und EndDate-Wert enthält. Lassen Sie uns sagen, ich habe:Fehlende Bereiche in einem Satz ausfüllen

Start  End 
1/15  1/20 
1/12  3/15 

ich eine Abfrage benötigen würde, die die folgende Zeile in die Daten werden ergänzt produziert:

1/21  2/11 

Die meisten anderen ähnlichen Fragen geht es um Lücken von einem Know gesetzt Füllung (wie ein Liste der Daten). In diesem Fall suche ich nur nach dem Anfang/Ende der fehlenden Daten.

+0

in Ausgabe ich glaube, Sie 1/21 bis 2/11 brauchen ... ist es richtig ? – Bhaarat

+0

Haben Sie in Ihrer Beispielausgabe 1/21 anstelle von 2/21 geschrieben? – user2023861

+0

Müssen Sie auch das Jahr zum Datum hinzufügen? – DVT

Antwort

2

Unter der Annahme, dass Sie 1/21 statt 2/21 zu schreiben bedeuten, hier ist ein Weg, es zu tun:

with dates as 
(
    select '2016-01-15' as dtStart, '2016-01-20' as dtEnd union all 
    select '2016-02-12', '2016-03-15' union all 
    select '2016-03-21', '2016-04-11' 
), 

calcs as 
(
    select 
     dateadd(day, 1, dtEnd) as rangeStart, 
     (select dateadd(day, -1, min(dtStart)) 
      from dates d2 where d2.dtStart > d.dtEnd) as rangeEnd 
    from dates d 
) 

select * 
from calcs c 
where c.rangeEnd >= c.rangeStart 

Die Tabelle dates ist nur drei Reihen von Probendaten. In der calcs Tabelle ist die rangeStart Spalte am nächsten Tag nach jedem dtEnd. Die Spalte rangeEnd nimmt die nächste dtStart und subtrahiert einen Tag. Schließlich hat die letzte Zeile eine Null, da jetzt nach dem letzten dtEnd ein Bereich fehlt. Daher ignoriere ich die Zeile mit dem Nullwert rangeEnd.

Bearbeiten: Wenn Sie mit der with Anweisung in meinem Code nicht vertraut sind, ist es ein CTE. Ich habe es hier verwendet, um schnell eine Tabelle mit einigen Beispieldaten (Datumsangaben) und einem Speicherort für Berechnungen (Berechnungen) zu erstellen.

Edit2: Da Sie erwähnt eine in Ihrem Kommentar verbinden mit, hier ist ein Weg, dies zu tun:

with dates as 
(
    select '2016-01-15' as dtStart, '2016-01-20' as dtEnd union all 
    select '2016-02-12', '2016-03-15' union all 
    select '2016-03-21', '2016-04-11' 
), 

calcs as 
(
    select 
     dateadd(day, 1, d1.dtEnd) as rangeStart, 
     dateadd(day, -1, min(d2.dtStart)) as rangeEnd 
    from dates d1 
    join dates d2 on d1.dtEnd < d2.dtStart 
    group by d1.dtEnd 
) 

select * 
from calcs 
where datediff(day, rangeStart, rangeEnd) >= 0 

Edit3:

+1

Diese Abfrage geht davon aus, dass es immer Lücken gibt, Sie müssen 'c.rangeEnd is not null' bearbeiten um' c.rangeEnd> = c.rangeStart' zu sein – MWillemse

+0

Danke, es war einfacher als ich dachte, ich hatte meinen Kopf steckte darauf, irgendwie durch eine Verbindung zu tun. Ich muss mehr Verarbeitung mit den fehlenden Bereichen durchführen, die zurück in die Quelldaten hinzugefügt werden, also sollte der CTE dafür perfekt funktionieren. – Kratz

+0

@Kratz, ich habe eine Lösung mit einem Join hinzugefügt, da du es erwähnt hast. Es verwendet eine ungewöhnliche Join-Bedingung mit einem '<' anstelle eines '='.Während dies mehrere Zeilen pro Treffer anstelle einer einzelnen Zeile zurückgibt, wie Sie es erwarten würden, wählen Sie mit der Aggregatfunktion 'group by' und' min' die rechte Zeile. Wenn Sie Probleme haben, es zu verstehen, führen Sie die Abfrage 'calcs' ohne die 'group by' und die' min' aus. – user2023861

0
select * from 
    (select DISTINCT t1.[end] + 1 'start', t2.start - 1 'end' 
      from yourtable t1 
      CROSS JOIN 
      yourtable t2 
       WHERE 
        EXISTS(SELECT 0 FROM yourtable t3 WHERE t3.[end] < t2.[start]) 
       AND 
        NOT EXISTS(SELECT 0 FROM yourtable t4 WHERE t4.start = t1.[end] + 1) 
       AND 
        NOT EXISTS(SELECT 0 FROM yourtable t5 WHERE T5.Start BETWEEN t1.[end] + 1 AND t2.start - 1 OR T5.[end] BETWEEN t1.[end] + 1 AND t2.start - 1) 
       AND 
        t1.[end] + 1 <= t2.start - 1 
    UNION 
     SELECT start,[end] from yourtable) dq 
order by start 
0
Declare @Table table (Start Date,[End] Date) 
Insert into @Table values 
('2016-01-15','2016-01-20'), 
('2016-02-12','2016-03-15') 

;with cteBase as (
    Select *,Gap=DateDiff(DD,Lag([End],1,Start) over (Order By Start),Start) From @Table 
) 
Select Start=DateAdd(DD,1+Gap*-1,Start),[End]=DateAdd(DD,-1,Start) from cteBase Where Gap<>0 

Returns

Start  End 
2016-01-21 2016-02-11 

Optional für vollständigen Datensatz

... 
Union All 
Select Start,[End] from cteBase 
Order by Start 
Verwandte Themen