如何在不使用 LOOP 的情况下计算取决于先前值的当前值?

Posted

技术标签:

【中文标题】如何在不使用 LOOP 的情况下计算取决于先前值的当前值?【英文标题】:How to calculate current value that depends on previous value without using LOOP? 【发布时间】:2021-09-09 13:57:49 【问题描述】:

我正在尝试在 SQL 中实现以下计算。目前,我正在使用带有 FOR LOOP 的 PL/SQL(或 PLPGSQL)和几个变量来计算每一行的值——当然,这是非常低效的。有没有办法使用窗口函数来完成这个?

对于第一行,当前值应该是某个固定值。对于以下行,

编辑:

相关公式:

Group-Return = IF(Period = 1, 0, SUMPRODUCT([Type-AA-Return]:[Type-BB-Return], [PREV Group-AA-Actual]:[PREV Group-BB-Actual] ))
Group-AA-Actual = IF(Period = 1, AA-Target, PREV Value/(1 + Group Return))

BB 和 CC 也是如此

样本数据:

前四列是静态数据。其他一切都是公式。

GROUP Period Type-AA-Return Type-BB-Return Group-Return Group-Growth AA-Target BB-Target CC-Target Group-AA-Actual Group-BB-Actual Group-CC-Actual
GROUP-ONE 1 0 0 0 1000 0.8 0.19 0.01 0.8 0.19 0.01
GROUP-ONE 2 -0.0040289 -0.0040209 -0.003987091 996.012909 0.8 0.19 0.01 0.799966419 0.189993551 0.010040031
GROUP-ONE 3 -0.003768282 -0.008660322 -0.004659904 991.371584 0.8 0.19 0.01 0.800683026 0.189229939 0.010087035
GROUP-ONE 4 -0.041907121 0.006951106 -0.032238963 959.410792 0.8 0.19 0.01 0.792684016 0.19689292 0.010423064
GROUP-ONE - - - - - - - - - - -
GROUP-ONE - - - - - - - - - - -
GROUP-ONE - - - - - - - - - - -
GROUP-ONE 12 -0.079204478 -0.000449001 -0.063450162 950.886857 0.8 0.19 0.01 0.75 0.24 0.01
GROUP-TWO 1 0 0 0 1000 0.8 0.19 0.01 0.8 0.19 0.01
GROUP-TWO 2 -0.0040289 -0.0040209 -0.003987091 996.012909 0.8 0.19 0.01 0.799966419 0.189993551 0.010040031
GROUP-TWO 3 -0.003768282 -0.008660322 -0.004659904 991.371584 0.8 0.19 0.01 0.800683026 0.189229939 0.010087035
GROUP-TWO 4 -0.041907121 0.006951106 -0.032238963 959.410792 0.8 0.19 0.01 0.792684016 0.19689292 0.010423064
GROUP-TWO - - - - - - - - - - -
GROUP-TWO - - - - - - - - - - -
GROUP-TWO - - - - - - - - - - -
GROUP-TWO 12 -0.079204478 -0.000449001 -0.063450162 950.886857 0.8 0.19 0.01 0.75 0.24 0.01

【问题讨论】:

您将需要使用实际数据样本和预期结果对此进行扩展。 “使用先前值计算的另一列中的值”对我来说不清楚。 我已添加该信息。显得笨重了许多。希望这会有所帮助。 除了样本数据之外,您还需要发布该数据的预期结果。还要解释你的Relevant Formulas,因为从我的角度来看,它们完全是胡言乱语。 这包含预期的输出 - 即 Group-Return 和 Group-AA-Actual 列。前四列是静态数据。其他一切都是公式。 【参考方案1】:

您可以使用 lag() 函数从前一行获取值吗?例如lag(GROUP-AA-ACTUAL)? 您可能还需要使用 partition by 来让每个组都能正常工作。 看看这里是否有帮助:oracle-lag-function-with-group-by

【讨论】:

【参考方案2】:

您可以使用recursive common table expression (CTE) 遍历一组行,这样:

输入示例数据:

CREATE TABLE t (value integer);

INSERT INTO t VALUES (10), (5), (15), (1), (4);

查询:

首先我生成行号,所以我可以一次迭代一行。然后我从第一行开始,得到下一行(第二行)。在UNION ALL 之后的子查询中,我一次得到一行(对于每一行,我可以访问以前的值(sq)和实际值(t_rn)。

在我的例子中calc_value(n) = calc_value(n-1) / (1 + value(n))

WITH RECURSIVE t_rn AS (SELECT ROW_NUMBER() OVER () AS rn, * FROM t),

               sq AS  (SELECT *, 10000.0 AS calc_value
                       FROM t_rn
                       WHERE rn = 1
                       
                       UNION ALL
                       
                       SELECT t_rn.rn, t_rn.value, (sq.calc_value / (1 + t_rn.value)) AS calc_value 
                       FROM sq
                       INNER JOIN t_rn ON sq.rn + 1 = t_rn.rn)

SELECT value, ROUND(calc_value, 2)
FROM sq
ORDER BY rn;

输出:

value calc_value
10 10000.00
5 1666.67
15 104.17
1 52.08
4 10.42

Fiddle!

【讨论】:

以上是关于如何在不使用 LOOP 的情况下计算取决于先前值的当前值?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不删除先前相同值的情况下选择具有重复项的列表中的特定数字?

如何在不覆盖先前值的情况下为同一个键设置多个值?

如何在不包括最后一个值(sql)的情况下计算值的平均值?

如何在不使用 for 循环的情况下填充二维数组?

如何在不影响先前视图的情况下更改 UINavigationBar 标题的名称?

如何在不关闭先前活动的情况下从通知中打开对话框样式的活动?