如何从月度回报中计算总回报

时间:2018-07-10 12:48:44

标签: tsql ssms recursive-query

我有一个表格,该表格具有每月收益,如下所示。 我的目标是计算出10000美元的投资增长。 下面显示的investment_growth列是我手动计算的。对于第一个月,10000 *(1 + return / 100)将是第一个值。结果值将在公式中替换为下个月的回报,依此类推。

有人可以通过查询帮助我实现这一目标。

谢谢

[每月收益表-投资增长列是目标]

enter image description here

2 个答案:

答案 0 :(得分:0)

您可以使用递归CTE来执行此操作,该CTE遍历您的表并可以引用以前计算的行。但是请注意,由于此行逐行循环,它可能会根据您的环境运行得相当慢:

declare @t table (FundName nvarchar(5),ReturnRate decimal(5,2), EndDate date);
insert into @t values('FundA',1.2,'20171231'),('FundA',-0.7,'20180131'),('FundA',1.3,'20180228'),('FundA',-2.3,'20180331'),('FundA',2.5,'20180430'),('FundA',1.9,'20180531'),('FundA',0.8,'20180630'),('FundB',1.1,'20171231'),('FundB',-0.4,'20180131'),('FundB',1.6,'20180228'),('FundB',-1.3,'20180331'),('FundB',2.0,'20180430'),('FundB',0.9,'20180531'),('FundB',0.8,'20180630');

declare @InitialInvestment int = 10000;

with rn as        -- Apply a row number to each Fund, ordered by EndDate so the first row can be used as the anchor in the Recursive CTE below.
(
    select FundName
            ,ReturnRate
            ,EndDate
            ,row_number() over (partition by FundName order by EndDate) as rn
    from @t
)
,r as
(
    select FundName        -- Select just the first rows for each fund and calculate the Investment Growth
            ,ReturnRate
            ,EndDate
            ,rn
            ,cast(@InitialInvestment * (1 + (ReturnRate/100)) as decimal(20,10)) as InvestmentGrowth
    from rn
    where rn = 1

    union all

    select r.FundName      -- Then row by row, fetch the next and calculate the Investment Growth by referencing the previous row in the dataset
            ,rn.ReturnRate
            ,rn.EndDate
            ,rn.rn
            ,cast(r.InvestmentGrowth * (1 + (rn.ReturnRate/100)) as decimal(20,10)) as InvestmentGrowth
    from r
        join rn
            on r.FundName = rn.FundName
                and r.rn = rn.rn-1
)
select FundName
    ,ReturnRate
    ,EndDate
    ,InvestmentGrowth
from r
order by FundName
        ,EndDate;

输出:

+----------+------------+------------+------------------+
| FundName | ReturnRate |  EndDate   | InvestmentGrowth |
+----------+------------+------------+------------------+
| FundA    |       1.20 | 2017-12-31 | 10120.0000000000 |
| FundA    |      -0.70 | 2018-01-31 | 10049.1600000000 |
| FundA    |       1.30 | 2018-02-28 | 10179.7990800000 |
| FundA    |      -2.30 | 2018-03-31 |  9945.6637011600 |
| FundA    |       2.50 | 2018-04-30 | 10194.3052936890 |
| FundA    |       1.90 | 2018-05-31 | 10387.9970942691 |
| FundA    |       0.80 | 2018-06-30 | 10471.1010710233 |
| FundB    |       1.10 | 2017-12-31 | 10110.0000000000 |
| FundB    |      -0.40 | 2018-01-31 | 10069.5600000000 |
| FundB    |       1.60 | 2018-02-28 | 10230.6729600000 |
| FundB    |      -1.30 | 2018-03-31 | 10097.6742115200 |
| FundB    |       2.00 | 2018-04-30 | 10299.6276957504 |
| FundB    |       0.90 | 2018-05-31 | 10392.3243450122 |
| FundB    |       0.80 | 2018-06-30 | 10475.4629397723 |
+----------+------------+------------+------------------+

答案 1 :(得分:0)

您可以使用“ Quirky Update”方法

一些测试数据

DECLARE @t TABLE ( [name] NVARCHAR(10), [return] DECIMAL(3,1), end_date DATE
                   , InvestmentGrowth DECIMAL(12,5) DEFAULT 0)
INSERT INTO @t
([name],[return],end_date)
VALUES
('FundA', 1.2, '20171231')
,('FundA', -0.7, '20180131')
,('FundA', 1.3, '20180228')
,('FundA', -2.3, '20180331')

投资始于10000

DECLARE @InvestmentAmount DECIMAL(12,5) = 10000

古怪的更新位

UPDATE @t
    SET @InvestmentAmount = InvestmentGrowth = @InvestmentAmount * (1+([T].[return]/100))
    FROM @t T;

name    return  end_date    InvestmentGrowth
FundA   1.2     2017-12-31  10120.00000
FundA   -0.7    2018-01-31  10049.16000
FundA   1.3     2018-02-28  10179.79908
FundA   -2.3    2018-03-31  9945.66370