SQL Server

时间:2017-12-11 11:59:02

标签: sql sql-server recursion common-table-expression

我的表格包含两条信息 BusinessDate DailyPerf ,其中DailyPerf显示我正在跟踪的价格值的百分比变化。数据的前几行看起来像这样

BusinessDate   DailyPerf 
Jan 3, 2017     -0.0356%
Jan 4, 2017     -0.4325%
Jan 5, 2017     -0.3953%
Jan 6, 2017     -0.8469%
Jan 9, 2017     -0.5050%

我要做的是计算另一列 YearFac ,它显示我离开的初始值的当前百分比

在Excel中完成数据将如下所示:

BusinessDate DailyPerf  YearFac
Jan 2, 2017  NULL       100%
Jan 3, 2017  -0.0356%   99.9644%
Jan 4, 2017  -0.4325%   99.5321%
Jan 5, 2017  -0.3953%   99.1386%
Jan 6, 2017  -0.8469%   98.2989%
Jan 9, 2017  -0.5050%   97.8025%

因此,我需要使用100%的YearFac来填充查询,然后递归计算因子。需要注意的是,日期不一定是连续的(周末或节假日没有条目) - 所以我不能认为next day = this day + 1只是第二天是下一个更大的日期

我尝试了以下

WITH   cte
AS     (
        SELECT cast(1 as int) RowCnt,
               cast('3 jan 2017' as date) BusinessDate, 
               cast(1.0 as float) YearFac -- anchor member
        UNION ALL
        select  cast(ROW_NUMBER() OVER(ORDER BY p.BusinessDate ASC) + 1 as int) as RowCnt,
                p.BusinessDate,                                                       -- recursive member
                cast(cte.YearFac*(1.0 + p.DailyPerc) as float) YearFac
        from cte
        inner join dbo.MsfsDailyPnl p 
        on 
        cte.RowCnt = ROW_NUMBER() OVER(ORDER BY p.BusinessDate ASC) + 1
        where p.BusinessDate < sysutcdatetime()
       )
SELECT RowCnt,BusinessDate, YearFac
FROM   cte

但是,当然,这会失败,因为我无法在连接中引用行号。任何人都可以建议进行修改以使此查询起作用吗?

3 个答案:

答案 0 :(得分:1)

使用累积总和:

select BusinessDate, DailyPerf,
       1 - exp(sum(log(1 + DailyPerf)) over (order by BusinessDate desc)
from (select cast('2017-01-03' as date) as BusinessDate, cast(0 as float) as DailyPerf
      union all
      select BusinessDate, DailyPerf from dbo.MsfsDailyPnl
     ) p;

答案 1 :(得分:1)

使用窗口功能

select *, sum(DailyPerf) over (order by BusinessDate) + 100 YearFac 
from (
     select dateadd(day, -1, min(BusinessDate)) BusinessDate, 0  DailyPerf from data
     union all 
     select * from data) t

dbfiddle demo

<强> RESULT

BusinessDate        DailyPerf   YearFac
-------------------------------------------
02/01/2017 00:00:00 0.0000      100.0000
03/01/2017 00:00:00 -0.0356     99.9644
04/01/2017 00:00:00 -0.4325     99.5319
05/01/2017 00:00:00 -0.3953     99.1366
06/01/2017 00:00:00 -0.8469     98.2897
09/01/2017 00:00:00 -0.5050     97.7847

答案 2 :(得分:0)

以下是您可能想要尝试的内容。我还附上了表的定义,因此你知道它的外观以及可以轻松完成任务的内容。

declare @x table(BusinessDate date, DailyPerf float)
insert into @x values
('Jan 2, 2017',     NULL),
('Jan 3, 2017',     -0.0356),
('Jan 4, 2017',     -0.4325),
('Jan 5, 2017',     -0.3953),
('Jan 6, 2017',     -0.8469),
('Jan 9, 2017',     -0.5050)

select *,
    100 + SUM(isnull(DailyPerf,0)) over (partition by (select null) order by 
        BusinessDate rows between unbounded preceding and current row)
from @x