计算SQL Server

时间:2017-09-13 02:41:35

标签: sql-server sql-server-2012

我目前正在尝试计算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。

有谁知道如何让它以有效的方式返回我想要的结果?

1 个答案:

答案 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