返回日期范围内的非重叠记录
Returning non-overlapping records within a date range
我有以下数据。我查看了很多关于重叠和非重叠日期的主题,但 none 似乎对我有所帮助。
===============================
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
===============================
从这个 table 使用 SQL 查询我想 return 重叠日期中的第一条记录
或者基本上
===============================
PK | StartDate | EndDate
===============================
1 | 2016-05-01 | 2016-05-02
3 | 2016-05-03 | 2016-05-04
5 | 2016-05-07 | 2016-06-08
===============================
我一直在为这个查询苦苦挣扎,想知道这是否真的可行而不会对性能造成太大影响,如果在后端完成或使用 SQL 查询是否更好,因为我相信我在后端做会更容易。
需要加入以首先找到所有重叠的列中的日期,然后只找到 MIN(dates)。
重叠日期范围 Start/End 的最小值
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
这可以通过创建一个新列并将其分区以仅获取第一行来实现。
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
我有以下数据。我查看了很多关于重叠和非重叠日期的主题,但 none 似乎对我有所帮助。
===============================
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
===============================
从这个 table 使用 SQL 查询我想 return 重叠日期中的第一条记录 或者基本上
===============================
PK | StartDate | EndDate
===============================
1 | 2016-05-01 | 2016-05-02
3 | 2016-05-03 | 2016-05-04
5 | 2016-05-07 | 2016-06-08
===============================
我一直在为这个查询苦苦挣扎,想知道这是否真的可行而不会对性能造成太大影响,如果在后端完成或使用 SQL 查询是否更好,因为我相信我在后端做会更容易。
需要加入以首先找到所有重叠的列中的日期,然后只找到 MIN(dates)。
重叠日期范围 Start/End 的最小值
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
这可以通过创建一个新列并将其分区以仅获取第一行来实现。
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