如何在SQL函数中计算不同的趋势线类型

时间:2019-04-25 12:42:59

标签: sql-server

我一直在寻找一种很好的方法来为桌面应用程序的仪表板图计算出像趋势线一样的excel。

最常见的趋势类型必须类似

Type = 1 Linear Y = a + b*X
Type = 2 EXponential Y = a*e^(b*X)   
Type = 3 Logarithmic Y = a + b*ln(X)
Type = 4 Power Y = a*X^b

这就是我解决问题的方式。

2 个答案:

答案 0 :(得分:2)

正如我在其他评论中提到的那样,可以将其写为内联TVF,而不是多行TVF。我从字面上看已经采用了OP的解决方案,但是,几个CTE允许我们这样做:

CREATE FUNCTION dbo.tvf_TrendLine (@Type tinyint,
                                   @Rawdata XYTableType READONLY)
RETURNS TABLE
AS RETURN
    WITH xy AS(
    SELECT CONVERT(decimal(38,10),COUNT(*)) AS n,
           CONVERT(decimal(38,10),SUM(CASE WHEN @Type IN (3,4) THEN LOG(X) ELSE X END)) AS x,
           CONVERT(decimal(38,10),SUM(CASE WHEN @Type IN (3,4) THEN LOG(X) * LOG(X) ELSE X * X END)) AS x2,
           CONVERT(decimal(38,10),SUM(CASE WHEN @Type IN (2,4) THEN LOG(Y) ELSE Y END)) AS y,
           CONVERT(decimal(38,10),SUM(CASE WHEN @Type IN (2,4) THEN LOG(Y) * Y ELSE Y * Y END)) AS y2,
           CONVERT(decimal(38,10),SUM(CASE WHEN @Type = 2 THEN X * LOG(Y) WHEN @Type = 3 THEN LOG(X) * Y WHEN @Type = 4 THEN LOG(X) * LOG(Y) ELSE X * Y END)) AS xy
        FROM @RawData
        WHERE Y IS NOT NULL),
    ab AS(
        SELECT n,
               x,
               x2,
               y,
               Y2,
               xy,
               CONVERT(decimal(38,10),CASE WHEN @Type IN (2,4) THEN EXP((x2 * y - x * xy) / (n * x2 - x * x))
                                           ELSE (x2 * y - x * xy) / (n * x2 - x * x)
               END) AS a,
               CONVERT(decimal(38,10),(n * xy - x * y) / (n * x2 - x * x)) AS b
        FROM xy)
    SELECT rd.X,
           rd.Y,
           CASE
                WHEN @Type = 2 THEN ab.a * EXP(LOG(EXP(1)) * (ab.b * rd.X))
                WHEN @Type = 3 THEN ab.a + ab.b * LOG(rd.X)
                WHEN @Type = 4 THEN ab.a * EXP(LOG(rd.X) * ab.b)
                ELSE ab.a + ab.b * rd.X
           END AS Yt
    FROM @Rawdata rd
         CROSS JOIN ab;
GO

这将返回与OP答案完全相同的结果。

答案 1 :(得分:1)

我们需要输入类型才能使其成为SQL函数

CREATE Type XYTableType 
AS TABLE (X float, Y float)
如果要使用时间序列,

X可以是日期时间。 我试图使此功能尽可能简单

create FUNCTION dbo.fn_TrendLine(@Type TINYINT, @raw_data XYTableType READONLY)
RETURNS @TrendTable TABLE(X float, Y float, Yt float)
AS
BEGIN
    DECLARE @n DECIMAL(38, 10),
        @x DECIMAL(38, 10),
        @x2 DECIMAL(38, 10),
        @y DECIMAL(38, 10),
        @xy DECIMAL(38, 10),
        @y2 DECIMAL(38, 10),
        @a DECIMAL(38, 10),
        @b DECIMAL(38, 10)

    SELECT  
    @n=COUNT(*),
    @x= sum(CASE
            WHEN @Type = 2 THEN X
            WHEN @Type = 3 THEN LOG(X)
            WHEN @Type = 4 THEN LOG(X)
            ELSE X
            END),
    @x2=sum(CASE
            WHEN @Type = 2 THEN X * X
            WHEN @Type = 3 THEN LOG(X) * LOG(X)
            WHEN @Type = 4 THEN LOG(X) * LOG(X)
            ELSE X * X
            END),
    @y= sum(CASE
            WHEN @Type = 2 THEN LOG(Y)
            WHEN @Type = 3 THEN Y
            WHEN @Type = 4 THEN LOG(Y)
            ELSE Y
            END),
    @xy=sum(CASE
            WHEN @Type = 2 THEN X * LOG(Y)
            WHEN @Type = 3 THEN LOG(X) * Y
            WHEN @Type = 4 THEN LOG(X) * LOG(Y)
            ELSE X * Y
            END),
    @y2=sum(CASE
            WHEN @Type = 2 THEN LOG(Y) * LOG(Y)
            WHEN @Type = 3 THEN Y * Y
            WHEN @Type = 4 THEN LOG(Y) * LOG(Y)
            ELSE Y * Y
            END)
    FROM @raw_data
    where Y is not null

    set @a = (@x2 * @y - @x * @xy) / (@n * @x2 - @x * @x)
    set @b = (@n * @xy - @x * @y) / (@n * @x2 - @x * @x )
    if @Type in (2,4)
        set @a = exp(@a)

    INSERT INTO @TrendTable(X, Y, Yt)
    SELECT  X,Y,
        Yt= case 
            WHEN @Type = 2 THEN @a *exp(log(exp(1))*(@b * X))
            WHEN @Type = 3 THEN @a + @b * LOG(X)
            WHEN @Type = 4 THEN @a * exp(log(X)*@b) 
            ELSE @a + @b * X
            end
    from @raw_data

    RETURN
END

这是一个例子

DECLARE @raw_data XYTableType
insert into @raw_data
values (1,1.15),(2,1.82),(3,3.13),(4,4.28),(5,4.67),(6,5.79),(7,7.81),(8,8.35),(9,9.40),(10,9.98),(11,5.79),(12,7.81),(13,8.35),(14,9.40),(15,null),(16,null)
select * from dbo.fn_TrendLine(1, @raw_data)
select * from dbo.fn_TrendLine(2, @raw_data)
select * from dbo.fn_TrendLine(3, @raw_data)
select * from dbo.fn_TrendLine(4, @raw_data)

x15和x16用于推断。 您只需复制结果并将其粘贴到excel工作表中即可使用图形或内置的excel函数进行检查。 我必须这样说;

否:类型3,4不能与负X值一起使用,类型2,4不能与负Y值一起使用。在计算某些类型之前,准备数据很重要。