如何从重叠日期中获取单独的间隔
How to get seperate intervals from overlapping dates
我有 table 有开始日期和结束日期,如下所示
drop table if exists #Temp
select *
into #Temp
from (values (1, 1, '2011-10-09', '2011-10-20'),
(2, 1, '2011-10-14', '2011-10-30'),
(3, 1, '2012-05-21', '2012-05-25')
) as value (id, userId, d1, d2)
这给了我这个 initial table:
id userId d1 d2
1 1 2011-10-09 2011-10-20
2 1 2011-10-14 2011-10-30
3 1 2012-05-21 2012-05-25
问题:我想要实现的是从这 2 个重叠日期中获得 3 个间隔。如何实现?
select *
from
#Temp t1
join #Temp t2
on t1.userId = t2.userId
and t1.id != t2.id
where
t1.d1 <= t2.d2
and t1.d2 >= t2.d1
order by t1.d1
给我
id userId d1 d2 id userId d1 d2
1 1 2011-10-09 2011-10-20 2 1 2011-10-14 2011-10-30
2 1 2011-10-14 2011-10-30 1 1 2011-10-09 2011-10-20
我不确定如何从这里继续。
我想要实现的是下面的table,其中重叠部分是分开的。
预期结果:
userId d1 d2
1 2011-10-09 2011-10-14
1 2011-10-14 2011-10-20
1 2011-10-20 2011-10-30
1 2012-05-21 2012-05-25
一种方法是对数据进行逆透视,然后对日期进行排序,然后再次对数据进行透视,排除一些记录。
WITH dataSource AS
(
select id, userId, d1
from #Temp t1
UNION ALL
select id, userId, d2
from #Temp t1
), DataSourceOrdered AS
(
SELECT
id, userId, d1,
row_number () OVER (PARTITION BY userId ORDER By d1) as rowid
FROM dataSource DS1
)
SELECT *
FROM DataSourceOrdered ds1
INNER JOIN DataSourceOrdered ds2
ON ds1.userId = ds2.[userId]
and ds1.[rowid] + 1 = ds2.[rowid]
and exists (
SELECT 1
FROM #Temp x
WHERE ds1.[d1] >= x.d1 and ds1.[d1] < x.d2 and ds1.userId = x.userId
)
根据您的实际数据,可能需要稍微更改一下,但对于当前的数据,它似乎可以工作。
这是一只丑陋的野兽,我必须承认。给出的答案好 100%。但是,这确实为您提供了所需的输出:
SELECT *
INTO #Temp
FROM (VALUES (1, 1, '2011-10-09', '2011-10-20'),
(2, 1, '2011-10-14', '2011-10-30'),
(3, 1, '2012-05-21', '2012-05-25')
) AS VALUE (id, userId, d1, d2)
WITH CTE AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY d1, d2) AS RowNumb
FROM #Temp
)
SELECT C.*,
C2.d1 AS C2D1,
C2.D2 AS C2D2,
CASE WHEN CAST (C2.d1 AS DATETIME ) < CAST (C.d2 AS DATETIME) THEN 1 ELSE 0 END AS InsertField
INTO #NewTable
FROM CTE AS C
LEFT JOIN CTE AS C2 ON C.RowNumb = C2.RowNumb - 1
SELECT * FROM #NewTable
SELECT id, userId, d1, CASE WHEN CAST (d2 AS DATETIME) < CAST (ISNULL (C2D1, '29000101') AS DATETIME) THEN d2 ELSE C2D1 END AS d2
INTO #Results
FROM #NewTable
UNION ALL
SELECT id, userid, C2D1, d2
FROM #NewTable
WHERE InsertField = 1
SELECT * FROM #NewTable
SELECT *, ROW_NUMBER() OVER (ORDER BY d1, d2) AS RowNumb
INTO #R
FROM #Results AS R
SELECT R.id,
R.userId,
CASE WHEN CAST (R.d1 AS DATETIME) < CAST (R2.d2 AS DATETIME) THEN R2.d2 ELSE R.d1 END AS D1,
R.d2
FROM #R AS R
LEFT JOIN #R AS R2 ON R.RowNumb = R2.RowNumb + 1
我有 table 有开始日期和结束日期,如下所示
drop table if exists #Temp
select *
into #Temp
from (values (1, 1, '2011-10-09', '2011-10-20'),
(2, 1, '2011-10-14', '2011-10-30'),
(3, 1, '2012-05-21', '2012-05-25')
) as value (id, userId, d1, d2)
这给了我这个 initial table:
id userId d1 d2
1 1 2011-10-09 2011-10-20
2 1 2011-10-14 2011-10-30
3 1 2012-05-21 2012-05-25
问题:我想要实现的是从这 2 个重叠日期中获得 3 个间隔。如何实现?
select *
from
#Temp t1
join #Temp t2
on t1.userId = t2.userId
and t1.id != t2.id
where
t1.d1 <= t2.d2
and t1.d2 >= t2.d1
order by t1.d1
给我
id userId d1 d2 id userId d1 d2
1 1 2011-10-09 2011-10-20 2 1 2011-10-14 2011-10-30
2 1 2011-10-14 2011-10-30 1 1 2011-10-09 2011-10-20
我不确定如何从这里继续。
我想要实现的是下面的table,其中重叠部分是分开的。
预期结果:
userId d1 d2
1 2011-10-09 2011-10-14
1 2011-10-14 2011-10-20
1 2011-10-20 2011-10-30
1 2012-05-21 2012-05-25
一种方法是对数据进行逆透视,然后对日期进行排序,然后再次对数据进行透视,排除一些记录。
WITH dataSource AS
(
select id, userId, d1
from #Temp t1
UNION ALL
select id, userId, d2
from #Temp t1
), DataSourceOrdered AS
(
SELECT
id, userId, d1,
row_number () OVER (PARTITION BY userId ORDER By d1) as rowid
FROM dataSource DS1
)
SELECT *
FROM DataSourceOrdered ds1
INNER JOIN DataSourceOrdered ds2
ON ds1.userId = ds2.[userId]
and ds1.[rowid] + 1 = ds2.[rowid]
and exists (
SELECT 1
FROM #Temp x
WHERE ds1.[d1] >= x.d1 and ds1.[d1] < x.d2 and ds1.userId = x.userId
)
根据您的实际数据,可能需要稍微更改一下,但对于当前的数据,它似乎可以工作。
这是一只丑陋的野兽,我必须承认。给出的答案好 100%。但是,这确实为您提供了所需的输出:
SELECT *
INTO #Temp
FROM (VALUES (1, 1, '2011-10-09', '2011-10-20'),
(2, 1, '2011-10-14', '2011-10-30'),
(3, 1, '2012-05-21', '2012-05-25')
) AS VALUE (id, userId, d1, d2)
WITH CTE AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY d1, d2) AS RowNumb
FROM #Temp
)
SELECT C.*,
C2.d1 AS C2D1,
C2.D2 AS C2D2,
CASE WHEN CAST (C2.d1 AS DATETIME ) < CAST (C.d2 AS DATETIME) THEN 1 ELSE 0 END AS InsertField
INTO #NewTable
FROM CTE AS C
LEFT JOIN CTE AS C2 ON C.RowNumb = C2.RowNumb - 1
SELECT * FROM #NewTable
SELECT id, userId, d1, CASE WHEN CAST (d2 AS DATETIME) < CAST (ISNULL (C2D1, '29000101') AS DATETIME) THEN d2 ELSE C2D1 END AS d2
INTO #Results
FROM #NewTable
UNION ALL
SELECT id, userid, C2D1, d2
FROM #NewTable
WHERE InsertField = 1
SELECT * FROM #NewTable
SELECT *, ROW_NUMBER() OVER (ORDER BY d1, d2) AS RowNumb
INTO #R
FROM #Results AS R
SELECT R.id,
R.userId,
CASE WHEN CAST (R.d1 AS DATETIME) < CAST (R2.d2 AS DATETIME) THEN R2.d2 ELSE R.d1 END AS D1,
R.d2
FROM #R AS R
LEFT JOIN #R AS R2 ON R.RowNumb = R2.RowNumb + 1