我目前正在尝试计算SQL Server中数据表的滚动平均值。
公式如下:
Set R = Number of preceding/rolling months to perform the average over
Set Result = 1
For each month in the set of data
Result *= 1 - ItemValue
End For
Result = 1 - POWER(Result, 12 / R)
数据如下所示:
TheDate ItemValue
2013-04-30 0.0123869967
2013-05-31 0.0216088580
2013-06-30 0.0087388750
2013-07-31 0.0155987010
2013-08-31 0.0237148940
2013-09-30 0.0258031340
2013-10-31 0.0210051110
2013-11-30 0.0175884900
对于R为3,我希望结果如下:
TheDate Result
2013-06-30 0.158315085
2013-07-31 0.169210386
2013-08-31 0.176340587
2013-09-30 0.231608981
2013-10-31 0.248350685
2013-11-30 0.229305289
为此,我想我可以创建一个TABLE类型,将前面3个日期传递给一个采用用户定义的表类型的函数。
CREATE TYPE core.udtRollingAverage AS TABLE
(
Value numeric(18,10)
)
然后我创建了一个函数来逐行执行计算:
ALTER FUNCTION dbo.CalculateRollingAverage(@RollingAverageTable core.udtRollingAverage READONLY)
RETURNS numeric(18,10)
AS
BEGIN
DECLARE @Result numeric(18,10) = 1;
DECLARE @Count int = (SELECT COUNT(*) FROM @RollingAverageTable);
SELECT @Result = @Result*(1-Value)
FROM @RollingAverageTable
SET @Result = 1 - POWER(@Result, 12 / @Count)
return @Result
END
对于单个测试用例,它返回了正确的结果:
DECLARE @MyTable AS core.udtRollingAverage
INSERT INTO @MyTable(Value)
VALUES(0.012386997),(0.021608858),(0.008738875);
SELECT dbo.CalculateRollingAverage(@MyTable)
--returns 0.1583150855
最后,我尝试将嵌套选择传递给用户定义的数据类型:
DECLARE @R int = 3
SELECT data_date, dbo.CalculateRollingAverage(
(SELECT TOP (@R) ItemValue
FROM dbo.MySourceTable
ORDER BY TheDate DESC
)
) AS Result
FROM dbo.MySourceTable
不幸的是,它抱怨说:
Operand type clash: numeric is incompatible with udtRollingAverage
我的前/滚动月份值可以达到12。
有谁知道如何让它以有效的方式返回我想要的结果?
答案 0 :(得分:1)
对于平均计算,您将采用多行(1 - Item Value)
的乘法
这与EXP ( SUM ( LOG ( value ) ) )
-- Sample Data
declare @tbl table (TheDate date, ItemValue decimal(18,10))
insert into @tbl select '2013-04-30', 0.0123869967
insert into @tbl select '2013-05-31', 0.0216088580
insert into @tbl select '2013-06-30', 0.0087388750
insert into @tbl select '2013-07-31', 0.0155987010
insert into @tbl select '2013-08-31', 0.0237148940
insert into @tbl select '2013-09-30', 0.0258031340
insert into @tbl select '2013-10-31', 0.0210051110
insert into @tbl select '2013-11-30', 0.0175884900
DECLARE @R int = 3
-- The Query
; with
cte as
(
select rn = row_number() over (order by TheDate), *
from @tbl t
)
select *
from cte c
cross apply
(
select ItemValue = 1 - POWER(EXP(SUM(LOG(1 - ItemValue))), 12.0 / @R)
from cte x
where x.rn > c.rn - 3
and x.rn <= c.rn
) a
where c.rn >= @R
order by c.rn
-- Result
3 2013-06-30 0.0087388750 0.158315084614417
4 2013-07-31 0.0155987010 0.16921038571785
5 2013-08-31 0.0237148940 0.176340587438388
6 2013-09-30 0.0258031340 0.231608980685967
7 2013-10-31 0.0210051110 0.248350685229337
8 2013-11-30 0.0175884900 0.229305288880144