使用递归 CTE 和/或窗口函数简化函数

Sun*_*tel 10 cte t-sql window-functions recursive sql-server-2016

我正在尝试提出一个递归 CTE 和/或窗口函数来创建一个函数。

几天后,我将函数归结为(伪代码),我拥有NB,并且需要生成E

E n = B n * (1 - SUM( E 1 , E 2 , ... E n-1 ))

例子:

?????????????????????????????????
? N ? B           ? E           ?
?????????????????????????????????
? 0 ? 0.142857143 ? 0.142857143 ?
? 1 ? 0.285714286 ? 0.244897959 ?
? 2 ? 0.285714286 ? 0.174927114 ?
? 3 ? 0.285714286 ? 0.124947938 ?
? 4 ? 0.285714286 ? 0.089248527 ?
? 5 ? 0.4         ? 0.089248527 ?
? 6 ? 0.666666667 ? 0.089248527 ?
? 7 ? 1           ? 0.044624264 ?
?????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

E 0 = 0.143 * (1 - 0) = 0.143
E 1 = 0.286 * (1 - 0.143) = 0.245
E 2 = 0.286 * (1 - (0.143 + 0.245)) = 0.175
E 3 = 0.280 * (1 - 0.143) + 0.245 + 0.175)) = 0.125
E 4 = 0.286 * (1 - (0.143 + 0.245 + 0.175 + 0.125)) = 0.089
E 5 = 0.400 * (1 - (0.143) + 0.09.0.145) + 0.09
E 6 = 0.667 * (1 - (0.143 + 0.245 + 0.175 + 0.125 + 0.089 + 0.089)) = 0.089
E 7 = 1.000 * (1 - (0.143 + 0.245) + 0.045) + 0.040 + 0.089) = 0.089

如果上表在 Excel 中,C2 = B2 * (1 - 0)(基础)和C3 = B3 * (1 - SUM(C$2:C2))(递归)

我试过的:

窗口函数

尝试过SUM(...) OVER(ORDER BY [N] ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),但无法递归引用该列。

递归 CTE

尝试了几次迭代:

?????????????????????????????????
? N ? B           ? E           ?
?????????????????????????????????
? 0 ? 0.142857143 ? 0.142857143 ?
? 1 ? 0.285714286 ? 0.244897959 ?
? 2 ? 0.285714286 ? 0.174927114 ?
? 3 ? 0.285714286 ? 0.124947938 ?
? 4 ? 0.285714286 ? 0.089248527 ?
? 5 ? 0.4         ? 0.089248527 ?
? 6 ? 0.666666667 ? 0.089248527 ?
? 7 ? 1           ? 0.044624264 ?
?????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

有些在 CTE 中有一个额外的列,但它只覆盖前 1 行,而第二行之后的结果是错误的。

带窗口函数的递归 CTE

从我尝试过的所有内容来看,似乎 CTE 的递归段是独立于其他结果计算的,并且SUM(...) OVER(...)仅适用于当前行。(关于上表, 的所有值E都是0.142857143)。

我认为这是因为这UNION ALL一切都是一次性发生的,而不是逐渐发生的。

替代解决方案

真正希望发生的是简化上述等式,和/或将其转换为迭代函数。

奖励:如果有人想知道此信息的来源,它可用于计算MACRS 折旧以用于税收目的。

Mar*_*ith 13

您需要一个额外的列来进行运行总计(fiddle)。

在下面 CTE 的递归部分中,R指的是“上一”行和A当前行,因此引用的列R是您的SUM(E1, E2, ... En-1).

WITH R
     AS (SELECT N,
                B,
                E = B,
                RunningTotalE = B
         FROM   A
         WHERE  N = 0
         UNION ALL
         SELECT A.N,
                A.B,
                E = A.B * ( 1 - R.RunningTotalE ),
                RunningTotalE = A.B * ( 1 - R.RunningTotalE ) + R.RunningTotalE
         FROM   R
                JOIN A
                  ON A.N = R.N + 1)
SELECT N,
       B,
       E = CAST(E AS DECIMAL(10,9))
FROM   R 
Run Code Online (Sandbox Code Playgroud)