Sql 在表中展开多个时间序列
我有一个包含多个时间序列的表,每个时间序列都与给定的ID相关联 像这样的Sql 在表中展开多个时间序列,sql,sql-server,time-series,Sql,Sql Server,Time Series,我有一个包含多个时间序列的表,每个时间序列都与给定的ID相关联 像这样的 +--------------------------------------+ | ID | start | end | value | +--------------------------------------+ | a | 01/01/2018 | 03/01/2018 | 5 | | a | 03/01/2018 | 04/01/2018 | 6 | | a | 0
+--------------------------------------+
| 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中是否可以从前一个表中获取后一个表,如果可以,请为我指出正确的方向
注意:每个时间序列是连续的,没有重叠的间隔 你可以试试这个
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
这种方法将原始表与0中的整数表联接,只选择那些小于日期差的整数。选定的每一行都提供扩展日期范围的一条记录。我假设原始数据中的日期间隔不超过9999天,但如果是这样,您可以通过添加一行来扩展整数表
编辑:我应该承认@slartidan在这个答案中生成整数列表的优雅方式交叉应用通常是一个更快的选择。我假设你可以假设一个范围内的月数是有限的,并且你的输入日期总是在一个月的第一天
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
我不明白。到目前为止,你尝试了什么?我不知道如何在没有某种循环和某种临时表的情况下填充它。你需要在查询语句中完成,或者它可以是一个过程/函数?你想创建数据来填补空白,对吗?哦,我找到了一种使用行数和DATEDIFF的方法。我在这里做实验,我会很快发布答案。谢谢你的时间。这在概念上/语法上对我来说似乎是最好的解决方案,但是它对于我的需要来说太慢了。输入表可以有O1e5行。谢谢你的评论。你是对的,对于你的问题,递归cte方法比静态数字乘法器表工作得慢。我使用这种方法,因为它足够快,可以满足我的需要。感谢您的时间。虽然有限间隔长度的假设是可以的,但从月初开始的范围不是。谢谢你的时间。很容易调整。这里最大的区别是使用交叉应用。
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])
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