Home > Mobile >  Returning non-overlapping records within a date range
Returning non-overlapping records within a date range

Time:03-31

I have the following data. I have looked over a lot of threads about overlapping and non-overlapping dates but none seemed to help me.

===============================
PK  | StartDate  |  EndDate
===============================
1   | 2016-05-01 |  2016-05-02
2   | 2016-05-02 |  2016-05-03
3   | 2016-05-03 |  2016-05-04
4   | 2016-05-04 |  2016-05-05
5   | 2016-05-07 |  2016-06-08
===============================

From this table with a SQL query I want to return the first record out of overlapping dates or basically

===============================
PK  | StartDate  |  EndDate
===============================
1   | 2016-05-01 |  2016-05-02
3   | 2016-05-03 |  2016-05-04
5   | 2016-05-07 |  2016-06-08
===============================

I have been struggling a lot with this query and was wondering if this is actually possible without too much of a hit on performance and whether its better if thats done on backend or with a SQL query because I believe it'd be easier for me to do it on the backend.

CodePudding user response:

This can be achieved by creating a new column and partitioning it to fetch only first rows.

declare @tbl table
(pk int identity,StartDate date,EndDate date)

insert into @tbl
values('2016-05-01','2016-05-02')
,('2016-05-02','2016-05-03')
,('2016-05-03','2016-05-04')
,('2016-05-04','2016-05-05')
,('2016-05-07','2016-06-08')

select pk,startdate,enddate  from(select pk,startdate,enddate 
,ROW_NUMBER()over(partition by [overlappingdates] order by startdate)rn
from(
select *,case when ROW_NUMBER()over(order by startdate) % 2 = 0 
then StartDate else EndDate end as [overlappingdates]
from
@tbl
)t
)t
where t.rn = 1

CodePudding user response:

Need to join to first find all overlapping, unpivot to dates in columns, then just find the MIN(dates).

Min of Start/End of Overlapping Date Ranges

DROP TABLE IF EXISTS #Dates
CREATE TABLE #Dates (PK INT IDENTITY(1,1),StartDate DATE,EndDate DATE)
INSERT INTO #Dates VALUES
('2016-05-01','2016-05-02')
,('2016-05-02','2016-05-03')
,('2016-05-03','2016-05-04')
,('2016-05-04','2016-05-05')
,('2016-05-07','2016-06-08')

SELECT A.PK
    ,StartDate = MIN(C.StartDate)
        ,EndDate = MIN(C.EndDate)
FROM #Dates AS A
INNER JOIN #Dates AS B
    ON A.PK < B.PK /*Only join 1 way and don't join to itself*/
    /*Find any overlap*/
    AND A.StartDate <= B.EndDate
    AND A.EndDate >= B.StartDate
CROSS APPLY (VALUES /*Puts in unpivoted(vertical) format so can run MIN() function*/
                (A.StartDate,A.EndDate)
                ,(B.StartDate,B.EndDate)
) AS C(StartDate,EndDate)           
GROUP BY A.PK
  • Related