我一直在寻找一种很好的方法来为桌面应用程序的仪表板图计算出像趋势线一样的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
这就是我解决问题的方式。
答案 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值一起使用。在计算某些类型之前,准备数据很重要。