1

Ich bin neu in SQL, also bitte mit mir und meinen armen Fähigkeiten; Ich möchte so viel wie möglich daraus lernen. DankSQL Server 2014 Merging Overlapping Datumsbereiche

Ich habe eine Tabelle mit 200.000 Zeilen in einer SQL Server 2014-Datenbank wie folgt aussehen:

CREATE TABLE DateRanges 
(
    Contract VARCHAR(8), 
    Sector VARCHAR(8), 
    StartDate DATE, 
    EndDate DATE 
); 

INSERT INTO DateRanges (Contract, Sector, StartDate, Enddate) 
    SELECT '111', '999', '01-01-2014', '03-31-2014' 
    union 
    SELECT '111', '999', '04-01-2014', '06-30-2014' 
    union 
    SELECT '111', '999', '07-01-2014', '09-30-2014' 
    union 
    SELECT '111', '999', '10-01-2014', '12-31-2014' 
    union 
    SELECT '111', '888', '08-01-2014', '08-31-2014' 
    union 
    SELECT '111', '777', '08-15-2014', '08-31-2014' 
    union 
    SELECT '222', '999', '01-01-2014', '03-31-2014' 
    union 
    SELECT '222', '999', '04-01-2014', '06-30-2014' 
    union 
    SELECT '222', '999', '07-01-2014', '09-30-2014' 
    union 
    SELECT '222', '999', '10-01-2014', '12-31-2014' 
    union 
    SELECT '222', '666', '11-01-2014', '11-30-2014' 
    UNION 
    SELECT '222', '555', '11-15-2014', '11-30-2014'; 

Wie Sie sehen können gibt es mehrere Überschneidungen für jeden Vertrag sein kann und was würde Ich mag das ist haben Ergebnis so

Contract Sector StartDate  EndDate 
    --------------------------------------------- 
    111  999  01-01-2014 07-31-2014 
    111  888  08-01-2014 08-14-2014 
    111  777  08-15-2014 08-31-2014 
    111  999  09-01-2014 12-31-2014 

    222  999  01-01-2014 10-31-2014 
    222  666  11-01-2014 11-14-2014 
    222  555  11-15-2014 11-30-2014 
    222  999  12-01-2014 12-31-2014 

ich nicht herausfinden kann, wie dies getan werden kann und die Beispiele, die ich auf dieser Seite ganz gesehen habe nicht mein Problem passen.

Vielen Dank für Ihre Hilfe und Unterstützung

+0

Wie wird EndDate '07 -31-2014' berechnet? Es ist nicht in Ihren Daten. –

+0

Dieses Datum ist nicht in den Daten enthalten. Es sollte als das letzte Datum berechnet werden, bevor ein neuer Datumsbereich mit einem anderen Sektor begonnen wird. –

+0

Ähnliche Fragen wurden oft vor z. https://stackoverflow.com/questions/2561130/merge-overlapping-date-intervals Sie können diesen Artikel für weitere detaillierte Erklärung, wie es zu lösen versuchen: https://www.experts-exchange.com/articles/ 3952/ranges-gaps-overlapps-for-number-and-date-ranges.html – Alex

Antwort

0

Diese Antwort Verwendung von ein paar verschiedene Techniken macht. Die erste ist eine , die eine Tabelle mit allen relevanten cal_date erstellt, die dann cross apply 'd mit eindeutigen Contract Werte erhält, um jede Kombination beider Werte zu erhalten. Die zweite ist wie lag und row_number, um eine Vielzahl von Dingen zu bestimmen, die in den Kommentaren unten aufgeführt sind. Schließlich, und wahrscheinlich am wichtigsten, zu bestimmen, wann eine Contract/Sector Kombination endet und der nächste beginnt.

Antwort:

--determine range of dates 
declare @bgn_dt date = (select min(StartDate) from DateRanges) 
    , @end_dt date = (select max(EndDate) from DateRanges) 

--use a recursive CTE to create a record for each day/Contract 
; with dates as 
    (
     select @bgn_dt as cal_date 
     union all 
     select dateadd(d, 1, a.cal_date) as cal_date 
     from dates as a 
     where a.cal_date < @end_dt 
    ) 
select d.cal_date 
, c.Contract 
into #contract_dates 
from dates as d 
cross apply (select distinct Contract from DateRanges) as c 
option (maxrecursion 0) 

--Final Select 
select f.Contract 
, f.Sector 
, min(f.cal_date) as StartDate 
, max(f.cal_date) as EndDate 
from (
    --Use the sum-over to obtain the Island Numbers 
    select dr.Contract 
    , dr.Sector 
    , dr.cal_date 
    , sum(dr.IslandBegin) over (partition by dr.Contract order by dr.cal_date asc) as IslandNbr 
    from (
     --Determine if the record is the start of a new Island 
     select a.Contract 
     , a.Sector 
     , a.cal_date 
     , case when lag(a.Sector, 1, NULL) over (partition by a.Contract order by a.cal_date asc) = a.Sector then 0 else 1 end as IslandBegin 
     from (
      --Determine which Contract/Date combinations are valid, and rank the Sectors that are in effect 
      select cd.cal_date 
      , dr.Contract 
      , dr.Sector 
      , dr.EndDate 
      , row_number() over (partition by dr.Contract, cd.cal_date order by dr.StartDate desc) as ConractSectorRnk 
      from #contract_dates as cd 
      left join DateRanges as dr on cd.Contract = dr.Contract 
             and cd.cal_date between dr.StartDate and dr.EndDate 
      ) as a 
     where a.ConractSectorRnk = 1 
     and a.Contract is not null 
     ) as dr 
    ) as f 
group by f.Contract 
, f.Sector 
, f.IslandNbr 
order by f.Contract asc 
, min(f.cal_date) asc 

Ausgang:

+----------+--------+------------+------------+ 
| Contract | Sector | StartDate | EndDate | 
+----------+--------+------------+------------+ 
|  111 | 999 | 2014-01-01 | 2014-07-31 | 
|  111 | 888 | 2014-08-01 | 2014-08-14 | 
|  111 | 777 | 2014-08-15 | 2014-08-31 | 
|  111 | 999 | 2014-09-01 | 2014-12-31 | 
|  222 | 999 | 2014-01-01 | 2014-10-31 | 
|  222 | 666 | 2014-11-01 | 2014-11-14 | 
|  222 | 555 | 2014-11-15 | 2014-11-30 | 
|  222 | 999 | 2014-12-01 | 2014-12-31 | 
+----------+--------+------------+------------+ 
+0

Vielen Dank ..... Es funktioniert super –

+0

Vielen Dank für Ihre großartige Arbeit und Probleme, meine Frage zu beantworten –