Question

L'exécution dans un problème.

J'ai une table définie pour maintenir les valeurs du Trésor par jour courbe de rendement .

Il est une table assez simple utilisé pour la recherche historique des valeurs.

Il y a notibly des lacunes dans le tableau de l'année 4, 6, 8, 9, 11-19 et 21-29.

La formule est assez simple en ce que pour calculer l'année 4 il est 0.5*Year3Value + 0.5*Year5Value.

Le problème est de savoir comment puis-je écrire un VIEW qui peut renvoyer les années manquantes?

Je pourrais probablement le faire dans une procédure stockée, mais le résultat final doit être vue.

Était-ce utile?

La solution

En prenant l'hypothèse par Tom H. que ce que vous voulez vraiment est une interpolation linéaire et le fait que non seulement des années, mais aussi mois manquent, vous devez baser tous les calculs sur MOIS, non ANNÉE.

Pour le code ci-dessous je suppose que vous avez 2 tables (dont un peut être calculé dans le cadre de la vue):

  • Rendement: contient des données réelles et stockées PeriodM nom plutôt que nombre de mois. Si vous stockez PeriodName là, vous auriez juste besoin de se joindre à la table:
  • Période (peut être calculé dans la vue comme indiqué) : nom période magasins et le nombre de mois, il représente

code suivant doit travailler (il vous suffit de créer une vue basée sur elle):

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'

Autres conseils

Vous pouvez essayer UNPIVOT d'obtenir les années et les valeurs dans une liste.

Alors ce syndicat aux années manquantes sélectionnez YearNo (Sélectionner YearValue où YearNo = YearNo-1) * 0,5 + (sélectionner YearValue où YearNo = YearNo + 1) * 0,5 AS YearValue de unpivotedlist où YearNo dans (notre liste des disparus des années)

puis la faire pivoter remonter à nouveau pour obtenir le format requis et de la pop dans une vue?

Je vais faire la supposition que vous voulez que la courbe se déplacer en douceur entre deux ans s'il y a un écart, donc si plus d'un an est vous manque ne voulez pas seulement en moyenne les deux années les plus proches. Voici ce que j'utiliserais probablement:

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

Vous pouvez réécrire cela en utilisant un CTE au lieu de la table Numbers (juste un tableau de nombres consécutifs). Vous pouvez également utiliser ou pas EXISTE avec les sous-requêtes MIN et MAX au lieu de la gauche sur YC_BOT2 Jointures externes et YC_TOP2 si vous vouliez faire. Certaines personnes trouvent cette méthode de confusion.

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

Pour les années manquantes cette requête prend la moyenne des années les plus proches trouvés.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top