输入我的程序
@time datetime -- Example: 27.07.2015 01:00
对于一些SELECT staments,我得到以下信息
@prevTime datetime -- Example: 27.07.2015 00:00
@prevValue real -- Example: 1
@nextTime datetime -- Example: 27.07.2015 02:00
@nextValue real -- Example: 3
现在我要计算
@value real -- In this Example the result should be: 2
我想使用"线性插值",请看这里:https://en.wikipedia.org/wiki/Linear_interpolation
有人能告诉我,这怎么做得最好? (我可以将日期时间转换成真实的吗?)
编辑:
我的第一个快速和肮脏的想法:
SET @value = @prevValue + ((@nextValue-@prevValue)/(CAST(@nextTime as real)-CAST(@prevTime as real))) * (CAST(@time as real)-CAST(@prevTime as real));
不能工作,因为日期时间 - >真实不精确
我的第二个快速和肮脏的想法:
SET @value = @prevValue + ((@nextValue-@prevValue)/(DATEDIFF(second,@nextTime,GETDATE())-DATEDIFF(second,@prevTime,GETDATE()))) * (DATEDIFF(second,@time,GETDATE())-DATEDIFF(second,@prevTime,GETDATE()));
工作,但如果有人告诉我一个更好的方式,我会很高兴
答案 0 :(得分:0)
我之前已将此类代码作为代码示例提交到SQL Server中心http://www.sqlservercentral.com/Forums/Topic872361-392-1.aspx
有问题的代码如下所示,执行标准的高斯消除法,将提供的数据点减少到一个等式,然后进行相应的推断:
-- Point type
CREATE TYPE Point AS TABLE (XCoordinate FLOAT, YCoordinate FLOAT);
GO
-- Curve fitting coefficient type
CREATE TYPE Coefficient AS TABLE (Multiplier FLOAT, PowerOfX INT);
GO
/**
* Function: fn_CurveFitPoints
* Author: Steven James Gray [ steve@cobaltsoftware.net ]
* Date: 24th February, 2010
* Version: 1.0
* Description:
* Takes a series of points in a table variant in POINT (X float, Y float) format and
* computes the n-1 power series curve fit using the Gauss-Jordan elimination process.
* Return value is a series of Multiplier, Power elements that can be used for producing
* an estimated Y value for any X value.
*
* Please refer to fn_ExtrapolateYValue(@xvalue, @coefficients) for a simple implementation
* of how to use the output of this function.
**/
CREATE FUNCTION dbo.fn_CurveFitPoints
(
@PointsToCurveFit POINT readonly
)
RETURNS @Result TABLE (Multiplier FLOAT, PowerOfX INT)
AS
BEGIN
-- ==========================================================================================
-- Stage 1 - Convert @PointsToFit into a matrix
-- ==========================================================================================
DECLARE @Matrix TABLE (MatrixRow INT, MatrixColumn INT, MatrixValue FLOAT);
DECLARE @TotalPoints INT = (SELECT COUNT(1) FROM @PointsToCurveFit);
WITH NumberProjectionCTE(CurrentNumber)
AS
(
SELECT 1
UNION ALL
SELECT 1+CurrentNumber FROM NumberProjectionCTE WHERE CurrentNumber < @TotalPoints
) INSERT INTO @Matrix
SELECT
Sequence-1, -- Each point gets it's own row
PWR.CurrentNumber-1, -- Column per power of X
CASE
WHEN PWR.CurrentNumber = 1 -- 1st column is X^0 = 1 Always
THEN 1
ELSE POWER(XCoordinate,PWR.CurrentNumber-1) -- Raise nth column to power n-1.
END
FROM
NumberProjectionCTE PWR, -- Cross join numeric point data and column indexes
(SELECT
ROW_NUMBER() OVER (ORDER BY XCoordinate, YCoordinate) AS Sequence,
XCoordinate,
YCoordinate
FROM
@PointsToCurveFit
) ValueData;
/* Append Y values as nth column */
INSERT INTO @Matrix
SELECT
ROW_NUMBER() OVER (ORDER BY XCoordinate, YCoordinate) - 1 AS Sequence,
@TotalPoints,
YCoordinate
FROM
@PointsToCurveFit;
-- ==========================================================================================
-- Stage 2 - Compute row echelon form of matrix
-- ==========================================================================================
DECLARE @lead INT = 0, @index INT = 0, @current FLOAT;
DECLARE @Rows INT = (SELECT MAX(MatrixRow) FROM @Matrix);
DECLARE @Columns INT = (SELECT MAX(MatrixColumn) FROM @Matrix);
DECLARE @Solved INT -- 0=Unsolvable, 1 = Solved
DECLARE @R INT = 0
WHILE @R <= @Rows
BEGIN
IF @Columns <= @lead
BEGIN
-- Cannot solve this one
SET @Solved = 0;
BREAK;
END;
SET @index = @R;
-- Determine if any row swaps are needed.
WHILE (SELECT MatrixValue FROM @Matrix WHERE MatrixRow = @index AND MatrixColumn = @lead) = 0
BEGIN
SET @index = @index + 1;
IF @Rows = @index
BEGIN
SET @index = @R;
SET @lead = @lead + 1;
IF @Columns = @lead
BEGIN
-- Cannot solve
SET @Solved = 0;
BREAK;
END;
END;
END;
-- Move this row to the correct position if needed.
IF @index <> @R
BEGIN
-- Swap rows
UPDATE @Matrix
SET MatrixRow = CASE MatrixRow
WHEN @R THEN @index
WHEN @index THEN @R
END
WHERE MatrixRow IN (@index, @R);
END;
-- Divide this row by it's lead column value, so that this row's lead is 1 (this will actually multiply/increase the value if lead <0)
DECLARE @Divisor FLOAT = (SELECT MatrixValue FROM @Matrix WHERE MatrixRow = @R AND MatrixColumn = @lead);
If @Divisor <> 1
BEGIN
UPDATE @Matrix SET MatrixValue = MatrixValue / @Divisor WHERE MatrixRow = @R;
END;
-- Update other rows and divide them by the appropriate multiple of this row in order to zero the current lead column.
UPDATE I
SET
MatrixValue = I.MatrixValue - (M.MatrixValue * R.MatrixValue)
FROM
@Matrix I
INNER JOIN @Matrix M ON M.MatrixRow = I.MatrixRow AND M.MatrixColumn = @lead
INNER JOIN @Matrix R ON R.MatrixColumn = I.MatrixColumn AND R.MatrixRow = @R AND R.MatrixRow <> I.MatrixRow
SET @lead = @lead + 1;
-- Move to next
SET @R = @R + 1;
END;
-- If we didn't bomb out, we're solved.
IF @Solved IS NULL
BEGIN
SET @Solved = 1
END;
-- ==========================================================================================
-- Stage 3 - Produce coefficients list (The final colum when in REF)
-- ==========================================================================================
IF @Solved = 1
BEGIN
INSERT INTO @Result (Multiplier, PowerOfX)
SELECT
MatrixValue,
MatrixRow
FROM @Matrix
WHERE MatrixColumn = @Columns;
END;
RETURN;
END;
GO
CREATE FUNCTION dbo.fn_ExtrapolateYValue
(
@XValue FLOAT,
@Coefficients Coefficient readonly
)
RETURNS FLOAT
AS
BEGIN
RETURN (SELECT SUM(Multiplier * POWER(@XValue, PowerOfX)) FROM @Coefficients);
END
例如:
DECLARE @PointsToCurveFit Point
-- A few simple X/Y values
INSERT INTO @PointsToCurveFit SELECT 1 , 6
INSERT INTO @PointsToCurveFit SELECT 2 , 3
INSERT INTO @PointsToCurveFit SELECT 3 , 2
-- Calculate the curve fitting coefficients
DECLARE @Coefficients Coefficient
INSERT INTO @Coefficients SELECT * FROM dbo.fn_CurveFitPoints(@PointsToCurveFit);
-- Shows that y= 11x^0 + 6x + x^2
SELECT * FROM @Coefficients;
-- Show the values for X=-5 to 5
WITH NumberCTE(Number)
AS
(
SELECT -5
UNION ALL
SELECT 1 + Number FROM NumberCTE WHERE Number < 5
) SELECT
Number AS XValue,
dbo.fn_ExtrapolateYValue(Number, @Coefficients) AS YValue
FROM NumberCTE;
在指定的代码中,我在X轴范围内推断曲线的函数从-5到+5。
答案 1 :(得分:0)
我对引擎系统的追求,降低焊接强度的方法,这就是我解决问题的方法-干净,简单。
CREATE TABLE WeldStrengthReduction
(
[Temperature] numeric(18,4) NOT NULL ,
[Reduction] numeric(18,4) NOT NULL ,
);
GO
insert into WeldStrengthReduction (Temperature,Reduction)
values
(510,1),
(538,0.95),
(566,0.91),
(593,0.86),
(621,0.82),
(649,0.77),
(677,0.73),
(704,0.68),
(732,0.64),
(760,0.59),
(788,0.55),
(816,0.5);
Go
Create Function WSRF(@Tempreture Numeric(18,4) ) returns Numeric(18,4)
as
begin
declare
@X1 Numeric(18,4),
@X2 Numeric(18,4),
@X3 Numeric(18,4),
@Y1 Numeric(18,4),
@Y2 Numeric(18,4),
@Y3 Numeric(18,4),
@pointer int
set @X2 = @Tempreture
declare @Templist table (id int IDENTITY(1,1), temp numeric(18,4), red numeric(18,4))
insert into @Templist select Temperature,Reduction from WeldStrengthReduction order by Temperature
select top 1 @X3 = temp, @Y3 = red, @pointer = id from @Templist where temp >= @Tempreture
if @pointer = 1 return @Y3 -- if incomming tempereture is below lowest, return according to lowewst temp
if @pointer is null return null -- if incomming tempereture is above highest, return null
select @X1 = temp, @Y1 = red from @Templist where id = @pointer - 1
set @Y2 = ((@X2-@X1)*(@Y3-@Y1))/(@X3 - @X1) + @Y1
return @Y2
end;
Go
select WSRF(772);
select WSRF(300);
select WSRF(1200);