varios update una tabla registros registro modificar importar eliminar datos comando borrar actualizar sql sql-server view interpolation linear

update - modificar datos de una tabla mysql



Vista del servidor SQL: cómo agregar filas faltantes mediante la interpolación (4)

Encontrándose en un problema.

Tengo una tabla definida para mantener los valores de la curva de rendimiento de tesorería diaria.

Es una tabla bastante simple utilizada para la búsqueda histórica de valores.

Hay algunos vacíos en la tabla en los años 4 , 6 , 8 , 9 , 11-19 y 21-29 .

La fórmula es bastante simple ya que para calcular el año 4 es 0.5*Year3Value + 0.5*Year5Value .

El problema es ¿cómo puedo escribir una VIEW que pueda devolver los años perdidos?

Probablemente podría hacerlo en un procedimiento almacenado, pero el resultado final debe ser una vista.


Podría intentar unpivot para obtener los años y valores en una lista.

Entonces unir esto a los años perdidos seleccione YearNo, (seleccione YearValue donde YearNo = YearNo-1) * 0.5 + (seleccione YearValue donde YearNo = YearNo + 1) * 0.5 AS YearValue de unpivotedlist donde YearNo in (nuestra lista de años perdidos)

Luego, píntelo de nuevo para obtener el formato que necesita y mostrarlo en una vista.


Tomando la suposición de Tom H. de que lo que realmente quieres es una interpolación lineal y el hecho de que no solo faltan años, sino también meses, necesitas basar cada cálculo en MES, no en AÑO.

Para el siguiente código, supongo que tiene 2 tablas (una de las cuales se puede calcular como parte de la vista):

  • Rendimiento: contiene datos reales y PeriodM almacenado en cantidad de meses en lugar de nombre. Si almacena PeriodName allí, solo necesita unirse a la mesa:
  • Período (se puede calcular en la vista como se muestra) : almacena el nombre del período y la cantidad de meses que representa

El siguiente código debe funcionar (solo necesita crear una vista basada en él):

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''


Voy a hacer la suposición de que desea que la curva se mueva suavemente entre dos años si hay un espacio, por lo que si falta más de un año, no desea promediar los dos años más cercanos. Esto es lo que probablemente usaría:

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

Puede reescribir esto usando un CTE en lugar de la tabla de Números (solo una tabla de números consecutivos). También podría usar NOT EXISTS o subqueries con MIN y MAX en lugar de LEFT OUTER JOINs en YC_BOT2 y YC_TOP2 si quisiera hacer eso. Algunas personas encuentran este método confuso.


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

Para los años perdidos, esta consulta toma el promedio de años más cercanos encontrados.