SQL Server 视图:如何使用插值添加缺失的行
-
06-09-2019 - |
题
遇到问题了。
我定义了一个表来保存每日金库的值 收益曲线.
这是一个非常简单的表,用于历史值查找。
与去年相比,该表存在一些明显差距 4
, 6
, 8
, 9
, 11-19
和 21-29
.
公式很简单,计算年份 4
它是 0.5*Year3Value + 0.5*Year5Value
.
问题是我怎样才能写一个 VIEW
那可以找回失踪的岁月吗?
我可能可以在存储过程中完成它,但最终结果需要是一个视图。
解决方案
采取假设 汤姆·H. 您真正想要的是线性插值,并且事实是,不仅缺少年份,还缺少月份,您需要将每个计算基于月份,而不是年份。
对于下面的代码,我假设您有 2 个表(其中一个可以作为视图的一部分进行计算):
- 屈服:包含真实数据并存储 M期 以月份数而不是名称。如果您存储 期间名称 在那里,你只需要加入桌子即可:
- 时期 (可以在如图所示的视图中计算): :存储期间名称及其代表的月数
以下代码必须有效(您只需要基于它创建一个视图):
WITH "Period" (PeriodM, PeriodName) AS (
-- // I would store it as another table basically, but having it as part of the view would do
SELECT 01, '1 mo'
UNION ALL SELECT 02, '2 mo' -- // data not stored
UNION ALL SELECT 03, '3 mo'
UNION ALL SELECT 06, '6 mo'
UNION ALL SELECT 12, '1 yr'
UNION ALL SELECT 24, '2 yr'
UNION ALL SELECT 36, '3 yr'
UNION ALL SELECT 48, '4 yr' -- // data not stored
UNION ALL SELECT 60, '5 yr'
UNION ALL SELECT 72, '6 yr' -- // data not stored
UNION ALL SELECT 84, '7 yr'
UNION ALL SELECT 96, '8 yr' -- // data not stored
UNION ALL SELECT 108, '9 yr' -- // data not stored
UNION ALL SELECT 120, '10 yr'
-- ... // add more
UNION ALL SELECT 240, '20 yr'
-- ... // add more
UNION ALL SELECT 360, '30 yr'
)
, "Yield" (ID, PeriodM, Date, Value) AS (
-- // ** This is the TABLE your data is stored in **
-- //
-- // value of ID column is not important, but it must be unique (you may have your PK)
-- // ... it is used for a Tie-Breaker type of JOIN in the view
-- //
-- // This is just a test data:
SELECT 101, 01 /* '1 mo'*/, '2009-05-01', 0.06
UNION ALL SELECT 102, 03 /* '3 mo'*/, '2009-05-01', 0.16
UNION ALL SELECT 103, 06 /* '6 mo'*/, '2009-05-01', 0.31
UNION ALL SELECT 104, 12 /* '1 yr'*/, '2009-05-01', 0.49
UNION ALL SELECT 105, 24 /* '2 yr'*/, '2009-05-01', 0.92
UNION ALL SELECT 346, 36 /* '3 yr'*/, '2009-05-01', 1.39
UNION ALL SELECT 237, 60 /* '5 yr'*/, '2009-05-01', 2.03
UNION ALL SELECT 238, 84 /* '7 yr'*/, '2009-05-01', 2.72
UNION ALL SELECT 239,120 /*'10 yr'*/, '2009-05-01', 3.21
UNION ALL SELECT 240,240 /*'20 yr'*/, '2009-05-01', 4.14
UNION ALL SELECT 250,360 /*'30 yr'*/, '2009-05-01', 4.09
)
, "ReportingDate" ("Date") AS (
-- // this should be a part of the view (or a separate table)
SELECT DISTINCT Date FROM "Yield"
)
-- // This is the Final VIEW that you want given the data structure as above
SELECT d.Date, p.PeriodName, --//p.PeriodM,
CAST(
COALESCE(y_curr.Value,
( (p.PeriodM - y_prev.PeriodM) * y_prev.Value
+ (y_next.PeriodM - p.PeriodM) * y_next.Value
) / (y_next.PeriodM - y_prev.PeriodM)
) AS DECIMAL(9,4) -- // TODO: cast to your type if not FLOAT
) AS Value
FROM "Period" p
CROSS JOIN "ReportingDate" d
LEFT JOIN "Yield" y_curr
ON y_curr.Date = d.Date
AND y_curr.PeriodM = p.PeriodM
LEFT JOIN "Yield" y_prev
ON y_prev.ID = (SELECT TOP 1 y.ID FROM Yield y WHERE y.Date = d.Date AND y.PeriodM <= p.PeriodM ORDER BY y.PeriodM DESC)
LEFT JOIN "Yield" y_next
ON y_next.ID = (SELECT TOP 1 y.ID FROM Yield y WHERE y.Date = d.Date AND y.PeriodM >= p.PeriodM ORDER BY y.PeriodM ASC)
--//WHERE d.Date = '2009-05-01'
其他提示
您可以尝试逆转置,以获得年和值的列表。
然后工会这对失踪多年 选择YearNo (选择YearValue其中YearNo = YearNo-1)×0.5 +(选择YearValue其中YearNo = YearNo + 1)* 0.5 AS YearValue 从unpivotedlist 其中YearNo在(我们的失踪多年列表)
然后转动回来了,让你需要的格式,并在视图中弹出它?
我要做出你想要的曲线平滑至两年移动,如果有一定的差距,因此,如果超过一年缺少你不希望只是平均最接近的两个年的猜测。这里就是我可能会使用:
SELECT
NUM.number AS year,
COALESCE(YC.val, YC_BOT.val + ((NUM.number - YC_BOT.yr) * ((YC_TOP.val - YC_BOT.val)/(YC_TOP.yr - YC_BOT.yr))))
FROM
dbo.Numbers NUM
LEFT OUTER JOIN dbo.Yield_Curve YC ON
YC.yr = NUM.number
LEFT OUTER JOIN dbo.Yield_Curve YC_TOP ON
YC.yr IS NULL AND -- Only join if we couldn't find a current year value
YC_TOP.yr > NUM.number
LEFT OUTER JOIN dbo.Yield_Curve YC_TOP2 ON
YC_TOP2.yr > NUM.number AND
YC_TOP2.yr < YC_TOP.yr
LEFT OUTER JOIN dbo.Yield_Curve YC_BOT ON
YC.yr IS NULL AND -- Only join if we couldn't find a current year value
YC_BOT.yr < NUM.number
LEFT OUTER JOIN dbo.Yield_Curve YC_BOT2 ON
YC_BOT2.yr < NUM.number AND
YC_BOT2.yr > YC_BOT.yr
WHERE
YC_TOP2.yr IS NULL AND
YC_BOT2.yr IS NULL AND
NUM.number BETWEEN @low_yr AND @high_yr
您可以使用CTE来代替数字表(只是一个连续的数字表)的改写本。你也可以使用NOT EXISTS或MIN和MAX,而不是左外连接上YC_BOT2和YC_TOP2如果你想这样做的子查询。有些人觉得这种方法混乱。
WITh cal(year) AS
(
SELECT 1 AS current_year
UNION ALL
SELECT year + 1
FROM cal
WHERE year < 100
)
SELECT CASE WHEN yield_year IS NULL THEN
0.5 *
(
SELECT TOP 1 yield_value
FROM yield
WHERE yield_year < year
ORDER BY
yield_year DESC
) +
0.5 *
(
SELECT TOP 1 yield_value
FROM yield
WHERE yield_year > year
ORDER BY
yield_year ASC
)
ELSE
yield_value
END
FROM cal
LEFT JOIN
yield
ON yield_year = year
有关缺失年这个查询所花费的发现最接近年的平均。
不隶属于 StackOverflow