我有一个包含多个时间序列的表,每个时间序列都与给定的ID相关联。
像这样的东西
+--------------------------------------+
| ID | start | end | value |
+--------------------------------------+
| a | 01/01/2018 | 03/01/2018 | 5 |
| a | 03/01/2018 | 04/01/2018 | 6 |
| a | 04/01/2018 | 06/01/2018 | 7 |
| b | 01/01/2018 | 04/01/2018 | 3 |
| b | 04/01/2018 | 06/01/2018 | 4 |
+--------------------------------------+
我们看到时间序列是由不规则的间隔定义的。我想"扩展"每个时间序列,所以系列中每天都有一行。
喜欢这个
+--------------------------------------+
| ID | start | end | value |
+--------------------------------------+
| a | 01/01/2018 | 02/01/2018 | 5 |
| a | 02/01/2018 | 03/01/2018 | 5 |
| a | 03/01/2018 | 04/01/2018 | 6 |
| a | 04/01/2018 | 05/01/2018 | 7 |
| a | 05/01/2018 | 06/01/2018 | 7 |
| b | 01/01/2018 | 02/01/2018 | 3 |
| b | 02/01/2018 | 03/01/2018 | 3 |
| b | 03/01/2018 | 04/01/2018 | 3 |
| b | 04/01/2018 | 05/01/2018 | 4 |
| b | 05/01/2018 | 06/01/2018 | 4 |
+--------------------------------------+
在SQL中可以从前者获得后一个表,如果可以,请指出我正确的方向?
注意:每个时间序列都是连续的,没有重叠的间隔。
答案 0 :(得分:2)
你可以试试这个。
DECLARE @T TABLE (ID VARCHAR(2), start DATE, [end] DATE, value INT )
INSERT INTO @T VALUES
( 'a', '01/01/2018', '01/03/2018', 5 ),
( 'a', '01/03/2018', '01/04/2018', 6 ),
( 'a', '01/04/2018', '01/06/2018', 7 ),
( 'b', '01/01/2018', '01/04/2018', 3 ),
( 'b', '01/04/2018', '01/06/2018', 4 )
;WITH CTE AS (
SELECT * FROM @T
UNION ALL
SELECT T.ID, DATEADD(DAY,1, CTE.start) Start, T.[end], T.value
FROM @T T
INNER JOIN CTE ON T.ID = CTE.ID AND T.value = CTE.value
AND DATEADD(DAY,1, CTE.start) < T.[end]
)
SELECT ID , start, DATEADD(DAY,1, start) [end], value FROM CTE
ORDER BY ID, start
结果:
ID start end value
---- ---------- ---------- -----------
a 2018-01-01 2018-01-02 5
a 2018-01-02 2018-01-03 5
a 2018-01-03 2018-01-04 6
a 2018-01-04 2018-01-05 7
a 2018-01-05 2018-01-06 7
b 2018-01-01 2018-01-02 3
b 2018-01-02 2018-01-03 3
b 2018-01-03 2018-01-04 3
b 2018-01-04 2018-01-05 4
b 2018-01-05 2018-01-06 4
答案 1 :(得分:1)
此方法将原始表与0中的整数表连接起来,仅选择那些小于日期之差的整数。选中的每一行都提供扩展日期范围的记录之一。我假设原始数据中的日期间隔不超过9999天,但如果是,您可以通过为tenthousands
等添加一行来扩展整数表。
SELECT T.ID,
DATEADD(D, V.N, T.Start) [start],
DATEADD(D, V.N+1, T.Start) [end],
T.Value
FROM YourTable T
JOIN (
SELECT ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n N
FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) ones(n),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) tens(n),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) hundreds(n),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) thousands(n)
) V
ON V.N < DATEDIFF(D, T.Start, T.[End])
编辑:我应该已经确认@slartidan用于在此答案中生成整数列表的优雅方式https://stackoverflow.com/a/33146869/1992793
答案 2 :(得分:0)
交叉申请通常是一个更快的选择。我假设你可以通过假设一个范围的月数限制来逃避,并假设你的输入日期总是在这个月的第一天。
with mnths as (
select *
from (values (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11)) as t(offset)
)
select *
from data
cross apply (
select dateadd(month, offset, start_dt) as expanded_start_dt
from mnths
where dateadd(month, offset, start_dt) < end_dt
) as m