SQL Server보기 : 보간을 사용하여 누락 된 행을 추가하는 방법
-
06-09-2019 - |
문제
문제가 발생합니다.
나는 매일 재무부의 가치를 보유하도록 정의 된 테이블이 있습니다. 수익률 곡선.
그것은 역사적 가치를 조회하는 데 사용되는 매우 간단한 테이블입니다.
연중 테이블에 약간의 간격이 있습니다. 4
, 6
, 8
, 9
, 11-19
그리고 21-29
.
공식은 연도를 계산하는 것이 매우 간단합니다. 4
이것의 0.5*Year3Value + 0.5*Year5Value
.
문제는 어떻게 a를 쓸 수 있다는 것입니다 VIEW
실종 된 해를 돌려 줄 수 있습니까?
저장된 절차에서 할 수는 있지만 최종 결과는보기가 필요합니다.
해결책
가정을 취합니다 톰 H. 당신이 정말로 원하는 것은 선형 보간이며 몇 년뿐만 아니라 몇 달이 빠졌다는 사실은 해가 아닌 한 달에 모든 계산을 기반으로해야합니다.
아래 코드의 경우 2 개의 테이블이 있다고 가정합니다 (그 중 하나는보기의 일부로 계산할 수 있음).
- 수율 : 실제 데이터를 포함하고 저장합니다 기간 이름보다는 이름이 있습니다. 당신이 저장한다면 기간 이름 거기에서, 당신은 단지 테이블에 가입하기 만하면됩니다.
- 기간 (표시와 같이보기에서 계산할 수 있습니다): 기간 이름과 그것이 나타내는 달 수를 저장합니다.
다음 코드는 작동해야합니다.
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'
다른 팁
목록에 연도와 가치를 얻기 위해 비트를 시도 할 수 있습니다.
그런 다음 누락 된 년까지 Universe Select Ongno (fealno = forgno-1) * 0.5 + (fealno = faverno + 1) * 0.5의 연말 값을 선택하십시오.
그런 다음 다시 회전하여 필요한 형식을 가져 와서보기로 팝업 하시겠습니까?
격차가있는 경우 곡선이 2 년 사이에 부드럽게 이동하기를 원한다고 추측 할 것입니다. 따라서 1 년 이상이 없으면 가장 가까운 2 년의 평균을 원하지 않습니다. 아마 내가 사용할 내용은 다음과 같습니다.
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를 사용 하여이 글을 다시 작성할 수 있습니다 (연속 숫자 표). 또한 YC_BOT2 및 YC_TOP2에서 왼쪽 외부 조인 대신 Min 및 Max와 함께 존재하지 않거나 하위 쿼리를 사용할 수도 있습니다. 어떤 사람들은이 방법이 혼란 스럽습니다.
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
누락 된 년 동안이 쿼리는 가장 가까운 해의 평균이 걸립니다.