Best way to interpolate values in SQL

前端 未结 3 1104
孤独总比滥情好
孤独总比滥情好 2020-12-15 08:16

I have a table with rate at certain date :

          Rates

Id  |     Date      |  Rate
----+---------------+-------
 1  |   01/01/2011  |  4.5
 2  |   01/04         


        
3条回答
  •  有刺的猬
    2020-12-15 08:40

    As @Mark already pointed out, the CROSS JOIN has its limitations. As soon as the target value falls outside the range of defined values no records will be returned.

    Also the above solution is limited to one result only. For my project I needed an interpolation for a whole list of x values and came up with the following solution. Maybe it is of interested to other readers too?

    -- generate some grid data values in table #ffffd:
    CREATE TABLE #ffffd (id int,x float,y float, PRIMARY KEY(id,x));
    INSERT INTO  #ffffd VALUES (1,3,4),(1,4,5),(1,6,3),(1,10,2),
                             (2,1,4),(2,5,6),(2,6,5),(2,8,2);
    SELECT * FROM #ffffd;                         
    
    -- target x-values in table #vals (results are to go into column yy):
    CREATE TABLE #vals (xx float PRIMARY KEY,yy float null, itype int);
    INSERT INTO  #vals (xx) VALUES (1),(3),(4.3),(9),(12);
    
    -- do the actual interpolation
    WITH valstyp AS (
      SELECT id ii,xx,
             CASE WHEN min(x)xx THEN 1 ELSE 2 END ELSE 0 END flag,
             min(x) xmi,max(x) xma 
      FROM #vals INNER JOIN #ffffd ON id=1 GROUP BY xx,id
    ), ipol AS (
      SELECT v.*,(b.x-xx)/(b.x-a.x) f,a.y ya,b.y yb 
      FROM valstyp v 
      INNER JOIN #ffffd a ON a.id=ii AND a.x=(SELECT max(x) FROM #ffffd WHERE id=ii 
                 AND (flag=0 AND x=xmi OR flag=1 AND xxmi OR flag=1 AND x>xx OR flag=2 AND x=xma))
    )
    UPDATE v SET yy=ROUND(f*ya+(1-f)*yb,8),itype=flag FROM #vals v INNER JOIN ipol i ON i.xx=v.xx;
    
    -- list the interpolated results table:
    SELECT * FROM #vals
    

    When running the above script you will get the following data grid points in table #ffffd

    id x  y 
    -- -- - 
    1  3  4 
    1  4  5 
    1  6  3 
    1  10 2 
    2  1  4 
    2  5  6 
    2  6  5 
    2  8  2 
    

    [[ The table contains grid points for two identities (id=1 and id=2). In my example I referenced only the 1-group by using where id=1 in the valstyp CTE. This can be changed to suit your requirements. ]]

    and the results table #vals with the interpolated data in column yy:

    xx  yy   itype 
    --- ---- ----- 
    1   2    0     
    3   4    0     
    4.3 4.7  1     
    9   2.25 1     
    12  1.5  2     
    

    The last column itype indicates the type of interpolation/extrapolation that was used to calculate the value:

    0:  extrapolation to lower end
    1:  interpolation within given data range
    2:  extrapolation to higher end
    

    This working example can be found here.

提交回复
热议问题