如何在SQL中计算各时间段的复合增长率_EXP与SUM OVER结合

云涛吖_8200

云涛吖_8200

2026-06-05

919人浏览

原创

复合增长率(cagr)不能用sum over,因其本质是几何平均而非算术累加;正确方法是用first_value和last_value提取首末值后套用幂运算公式,并以实际时间跨度(非行数)作分母。

如何在sql中计算各时间段的复合增长率_exp与sum over结合

复合增长率计算为什么不能直接用 SUM OVER?

因为复合增长率(CAGR)本质是几何平均增长,不是线性累加——SUM OVER 算的是算术累计和,强行套用会得出完全错误的结果。比如某指标连续三期为 100 → 120 → 96,真实复合增速是 (96/100)^(1/2) − 1 ≈ −2.02%,但用 SUM OVER 对「每期环比增长率」求和再除以期数,得到的是 (0.2 − 0.2)/2 = 0%,彻底失真。

真正可行的路径是:先用窗口函数拿到期初值和期末值,再套用幂运算公式。关键在于避免对增长率本身做窗口聚合。

用 FIRST_VALUE 和 LAST_VALUE 提取首尾值

这是最稳定、兼容性最好的方式,适用于 PostgreSQL、SQL Server、Oracle、BigQuery 等主流引擎(注意 MySQL 8.0+ 才支持完整窗口函数语义)。

  • FIRST_VALUE(value) OVER (PARTITION BY group_col ORDER BY time_col ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) 确保取到每个分组内时间轴上的第一个实际值(不是 NULL)
  • LAST_VALUE(value) OVER (PARTITION BY group_col ORDER BY time_col ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) 同理取末值;但注意默认 LAST_VALUE 的 window frame 是 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,必须显式重设 frame,否则拿不到真正的最后一个值
  • 时间列必须严格有序且无重复,否则需加 ROW_NUMBER() 辅助去重排序

示例(按年计算各产品 CAGR):

SELECT
  product,
  FIRST_VALUE(sales) OVER (PARTITION BY product ORDER BY year ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS base_sales,
  LAST_VALUE(sales) OVER (PARTITION BY product ORDER BY year ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS final_sales,
  COUNT(*) OVER (PARTITION BY product) - 1 AS n_years,
  POWER(final_sales * 1.0 / base_sales, 1.0 / NULLIF(n_years, 0)) - 1 AS cagr
FROM sales_history;

EXP(SUM(LN(...)) OVER ...) 的陷阱与适用场景

这个写法理论上等价于连乘积开方,即 EXP(SUM(LN(ratio)) OVER ...) 可还原出总倍数,再开 n 次方得 CAGR。但它只适用于「已知每期环比比率」的场景,且极易因数据质量问题崩掉:

求职精灵
求职精灵

一款AI办公效率工具,主要用于有见求职旗下AI求职平台,提供AI简历优化、AI模拟面试、岗位查询、职业规划等,适合需要提升相关任务效率的用户。

下载
  • 任意一期 ratio ≤ 0 → LN 报错(如 PostgreSQL 抛 invalid argument for logarithm)
  • 存在 NULL 或空值时,SUM 直接返回 NULL,整个链路中断
  • 浮点精度误差在长周期(>10 年)下可能放大,结果偏离手工验算值
  • MySQL 不支持 LN 窗口聚合(5.7/8.0 均不允许可聚合函数嵌套窗口函数),PostgreSQL 允许但需确保 ratio 列非空

仅建议在清洗干净的环比比率表上使用,且必须包 NULLIF 和 CASE WHEN 防御:

EXP(
  SUM(LN(CASE WHEN ratio > 0 THEN ratio END)) 
    OVER (PARTITION BY product ORDER BY year)
  / NULLIF(COUNT(*) OVER (PARTITION BY product) - 1, 0)
) - 1 AS cagr

时间跨度不连续时如何处理?

真实业务中常遇到断点(如某产品 2020、2022 年有数据,2021 年缺失)。此时不能简单用 COUNT(*) - 1 当作年数——必须用实际最大最小时间差:

  • 用 MAX(year) - MIN(year) 替代行数减一(前提是年份为整型或可减日期)
  • 若时间字段是 DATETIME,用 DATEDIFF('year', MIN(dt), MAX(dt))(BigQuery/SQL Server)或 EXTRACT(YEAR FROM MAX(dt)) - EXTRACT(YEAR FROM MIN(dt))(PostgreSQL)
  • 更严谨的做法是计算「实际天数差 / 365.25」作为年化指数,尤其跨多年度且需财务级精度时

漏掉这点,三年断续数据(2020→2022)会被误算成两年期 CAGR,结果偏高约 2–3%。

真正难的从来不是写对那个 POWER 表达式,而是确认分母用的是自然时间跨度,而不是数据库里恰好有几条记录。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

4023

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

851

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1049

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

5881

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

2803

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

5860

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

7801

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1070

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

932

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.4万人学习