SQL 服务器填补了时间序列的空白
SQL Server filling gaps in time series
我在 SQL 中遇到请求问题。
我有两个 table,一个代表日期向量,另一个代表不同证券价格的时间序列:
日期:
DateId
Date
1
2021-01-01
2
2021-01-02
3
2021-01-03
TimeSerie:
SecurityId
DateId
Value
1
1
0.25
1
3
0.32
2
1
0.41
2
2
0.67
时间序列可能有间隙,例如在上面的 table 中,SecurityId=1 在 DateId=2 处没有任何行,而 SecurityId=2 在 DateId=3 处没有任何行。
我需要构建一个请求,用时间序列中的最后一个值填补空白。
导致所有证券和所有日期的价值如下:
SecurityId
DateId
Value
1
1
0.25
1
2
0.25
1
3
0.32
2
1
0.41
2
2
0.67
2
3
0.67
我尝试开始用右连接匹配所有日期
SELECT * from [TimeSerie] px RIGHT JOIN Dates dt on dt.DateId = px.Dateid
不幸的是,这不起作用,因为始终存在 DateId 上的相等性匹配的安全性,所以我没有得到没有值的 TimeSeries 行。
我正在研究 SQL 服务器标准 2019,我的目标是基于单个查询的解决方案(避免使用临时 tables 或游标的过程)。
您可以使用 cross join
生成行,然后 left join
:
select d.*, s.*, ts.value
from dates d cross join
(select distinct securityid from timeseries) s left join
(select ts.*,
lead(ts.dateid) over (partition by securityid order by dateid) as next_dateid
from timeseries ts
) ts
on s.securityid = ts.securityid and
d.dateid >= ts.dateid and
(d.dateid < ts.next_dateid or ts.next_dateid is null);
这假设 dateid
是连续的,这似乎是一个合理的假设。
一种方法是使用 CTE 和窗口 COUNT
将数据分组,然后获取该组的 MAX
值:
--Sample data
WITH Dates AS(
SELECT *
FROM (VALUES(1,CONVERT(date,'2021-01-01')),
(2,CONVERT(date,'2021-01-02')),
(3,CONVERT(date,'2021-01-03')))D(DateID,[Date])),
TimeSerie AS(
SELECT *
FROM (VALUES(1,1,0.25),
(1,3,0.32),
(2,1,0.41),
(2,2,0.67))V(SecurityID,DateID,[Value])),
--Solution
DateSeries AS(
SELECT DISTINCT
D.DateID,
D.[Date],
TS.SecurityID
FROM Dates D
CROSS JOIN TimeSerie TS),
Groups AS(
SELECT DS.SecurityID,
DS.DateID,
TS.[value],
COUNT(TS.[Value]) OVER (PARTITION BY DS.SecurityID ORDER BY [Date]) AS Grp
FROM DateSeries DS
LEFT JOIN TimeSerie TS ON DS.SecurityID = TS.SecurityID
AND DS.DateID = TS.DateID)
SELECT G.SecurityID,
G.DateID,
MAX([Value]) OVER (PARTITION BY G.SecurityID, G.Grp) AS [Value]
FROM Groups G;
我在 SQL 中遇到请求问题。
我有两个 table,一个代表日期向量,另一个代表不同证券价格的时间序列:
日期:
DateId | Date |
---|---|
1 | 2021-01-01 |
2 | 2021-01-02 |
3 | 2021-01-03 |
TimeSerie:
SecurityId | DateId | Value |
---|---|---|
1 | 1 | 0.25 |
1 | 3 | 0.32 |
2 | 1 | 0.41 |
2 | 2 | 0.67 |
时间序列可能有间隙,例如在上面的 table 中,SecurityId=1 在 DateId=2 处没有任何行,而 SecurityId=2 在 DateId=3 处没有任何行。
我需要构建一个请求,用时间序列中的最后一个值填补空白。 导致所有证券和所有日期的价值如下:
SecurityId | DateId | Value |
---|---|---|
1 | 1 | 0.25 |
1 | 2 | 0.25 |
1 | 3 | 0.32 |
2 | 1 | 0.41 |
2 | 2 | 0.67 |
2 | 3 | 0.67 |
我尝试开始用右连接匹配所有日期
SELECT * from [TimeSerie] px RIGHT JOIN Dates dt on dt.DateId = px.Dateid
不幸的是,这不起作用,因为始终存在 DateId 上的相等性匹配的安全性,所以我没有得到没有值的 TimeSeries 行。
我正在研究 SQL 服务器标准 2019,我的目标是基于单个查询的解决方案(避免使用临时 tables 或游标的过程)。
您可以使用 cross join
生成行,然后 left join
:
select d.*, s.*, ts.value
from dates d cross join
(select distinct securityid from timeseries) s left join
(select ts.*,
lead(ts.dateid) over (partition by securityid order by dateid) as next_dateid
from timeseries ts
) ts
on s.securityid = ts.securityid and
d.dateid >= ts.dateid and
(d.dateid < ts.next_dateid or ts.next_dateid is null);
这假设 dateid
是连续的,这似乎是一个合理的假设。
一种方法是使用 CTE 和窗口 COUNT
将数据分组,然后获取该组的 MAX
值:
--Sample data
WITH Dates AS(
SELECT *
FROM (VALUES(1,CONVERT(date,'2021-01-01')),
(2,CONVERT(date,'2021-01-02')),
(3,CONVERT(date,'2021-01-03')))D(DateID,[Date])),
TimeSerie AS(
SELECT *
FROM (VALUES(1,1,0.25),
(1,3,0.32),
(2,1,0.41),
(2,2,0.67))V(SecurityID,DateID,[Value])),
--Solution
DateSeries AS(
SELECT DISTINCT
D.DateID,
D.[Date],
TS.SecurityID
FROM Dates D
CROSS JOIN TimeSerie TS),
Groups AS(
SELECT DS.SecurityID,
DS.DateID,
TS.[value],
COUNT(TS.[Value]) OVER (PARTITION BY DS.SecurityID ORDER BY [Date]) AS Grp
FROM DateSeries DS
LEFT JOIN TimeSerie TS ON DS.SecurityID = TS.SecurityID
AND DS.DateID = TS.DateID)
SELECT G.SecurityID,
G.DateID,
MAX([Value]) OVER (PARTITION BY G.SecurityID, G.Grp) AS [Value]
FROM Groups G;