2017-09-13 32 views
0

現在、SQL Serverのデータテーブルに対してローリング平均を計算しようとしています。次のように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) 

データは次のようになります3のRについて

TheDate  ItemValue 
2013-04-30 0.
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 

これはであるために、私は結果を期待:

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 

これを行うには、前の3つの日付をユーザー定義の関数に渡すTABLE型を作成できると考えましたテーブルタイプ。

CREATE TYPE core.udtRollingAverage AS TABLE 
(
    Value numeric(18,10) 
) 

はその後Iが行単位で行の計算を実行する関数を作成した。最後に

DECLARE @MyTable AS core.udtRollingAverage 
    INSERT INTO @MyTable(Value) 
    VALUES(0.),(0.021608858),(0.008738875); 
    SELECT dbo.CalculateRollingAverage(@MyTable) 
    --returns 0.1583150855 

:単一のテストケースについて

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 @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

あなたの平均的な計算のためには、これは完璧だことEXP (SUM (LOG (value)))

-- Sample Data 
declare @tbl table (TheDate date, ItemValue decimal(18,10)) 
insert into @tbl select '2013-04-30', 0.
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 
+0

としてInfactは同じである複数の行の(1 - Item Value)

値の乗算を取っています。私は同じ道を向いていました - 私はEXP(SUM(LOGトリック)、OUTER APPLYでCTEを作っていましたが、あなたのことは思いついた倍の速さです。 – tone