You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle中按年度计算百分比累计值的SQL实现问题

复利累计百分比计算SQL实现

需求规则

  • 源表tbl包含YEARS(年度)、PERCENTAGE(百分比值)字段
  • 按年度升序排列,逐年计算累计复利值存入ACCUMULATIVE列
  • 单期增长系数换算规则:PERCENTAGE / 100 + 1
  • 累计规则为各期增长系数连乘后减1,转回百分比格式,而非简单百分比求和
  • 预期结果参考:
YEARS,          PERCENTAGE,      ACCUMULATIVE
2010,           38.15%,           38.15%
2011,          -25.51%,           2.93%
2012,           -8.47%,           -5.80%
2013,           18.51%,           11.64%
2014,            -2.07%,           9.32%
2015,            16.27%,          27.11%
2016,           108.94%,         165.60%
2017,            29.67%,         244.41%

原有SQL错误点

  • 字段别名前后不匹配:内层别名定义为YEAR,外层排序引用YR,字段无法识别
  • 聚合逻辑错误:复利累计是系数连乘,不是百分比直接求和,不能用SUM(PERCENTAGE)实现
  • 窗口分区错误:内层按YEAR分区会将每年数据独立切割,无法实现跨年度累计
  • 缺失格式转换:没有将计算后的数值结果转回百分比展示格式

正确SQL写法

写法1:适用于支持乘积窗口函数的数据库(PostgreSQL 14+、BigQuery、Spark SQL等)

SELECT
  YEARS,
  PERCENTAGE,
  CONCAT(ROUND((cumulative_factor - 1) * 100, 2), '%') AS ACCUMULATIVE
FROM (
  SELECT
    YEARS,
    PERCENTAGE,
    -- 按年度排序,逐行累计乘以前期增长系数
    PRODUCT(PERCENTAGE / 100 + 1) OVER (
      ORDER BY YEARS
      ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS cumulative_factor
  FROM tbl
) AS t
ORDER BY YEARS;

写法2:适用于不支持PRODUCT窗口函数的数据库(MySQL、低版本PostgreSQL等)

利用对数性质ln(a*b) = ln(a) + ln(b),将乘积转换为求和计算,最后取指数还原结果:

SELECT
  YEARS,
  PERCENTAGE,
  CONCAT(ROUND((EXP(cumulative_ln_sum) - 1) * 100, 2), '%') AS ACCUMULATIVE
FROM (
  SELECT
    YEARS,
    PERCENTAGE,
    SUM(LN(PERCENTAGE / 100 + 1)) OVER (
      ORDER BY YEARS
      ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS cumulative_ln_sum
  FROM tbl
) AS t
ORDER BY YEARS;

注:如果PERCENTAGE字段是带%的字符串格式,需要先替换掉%符号转为数值再计算,例如MySQL中用CAST(REPLACE(PERCENTAGE, '%', '') AS DECIMAL(10,2))做转换。

内容的提问来源于stack exchange,提问作者Мариян Цветков

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 19:09:52