news 2026/5/1 4:51:23

用SQL实现三次指数平滑预测:递归与非递归两种解法详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用SQL实现三次指数平滑预测:递归与非递归两种解法详解

目录

一、三次指数平滑法基础

1.1 核心原理

1.2 数据源说明

二、解法一:递归CTE实现

2.1 完整代码

2.2 关键解析

三、解法二:非递归(LAG窗口函数)实现

3.1 完整代码

3.2 关键解析

四、两种解法对比

五、实战注意事项

六、总结


在时间序列预测领域,三次指数平滑法是处理非线性趋势数据的经典方法,广泛应用于零售额、销量、产值等经济数据的预测。相比于Python/R等数据分析语言,SQL作为数据存储与处理的核心工具,直接在数据库中实现该算法可减少数据迁移成本。本文将以“1960-1982年全国社会商品零售额预测”为例,详解递归CTE非递归(LAG窗口函数)两种SQL实现方式,覆盖核心逻辑、完整代码与实战解析。

一、三次指数平滑法基础

1.1 核心原理

三次指数平滑法通过对原始数据进行三次加权平滑,拟合非线性趋势,核心公式如下(平滑系数α通常取0.1~0.3,本文取0.3):

1.2 数据源说明

本文使用1960-1982年全国社会商品零售额数据(单位:亿元),目标是预测1983年(m=1)和1985年(m=3)的零售额,原始数据如下(注:1972/1975年数据疑似笔误,保留原始值):

年份196019611962...198019811982
零售额696.6607.7604.0...2140.02350.02570.0

二、解法一:递归CTE实现

递归CTE(WITH RECURSIVE)是处理“递推依赖”问题的经典方式,适合MySQL 8.0+/PostgreSQL等支持递归的数据库,核心思路是通过“初始值+递推逻辑”逐期计算平滑值。

2.1 完整代码

-- 1. 创建并插入原始数据 CREATE TABLE IF NOT EXISTS retail_sales ( year INT PRIMARY KEY, -- 年份 sales DECIMAL(10,1) -- 社会商品零售额(亿元) ); ​ INSERT INTO retail_sales (year, sales) VALUES (1960, 696.6), (1961, 607.7), (1962, 604.0), (1963, 604.5), (1964, 638.2), (1965, 670.3), (1966, 732.8), (1967, 770.5), (1968, 737.3), (1969, 801.5), (1970, 858.0), (1971, 929.2), (1972, 10233.0), (1973, 1106.7), (1974, 1163.6), (1975, 12711.0), (1976, 1339.4), (1977, 1432.8), (1978, 1558.6), (1979, 1800.0), (1980, 2140.0), (1981, 2350.0), (1982, 2570.0); ​ -- 2. 递归CTE计算平滑值并预测 WITH RECURSIVE -- 步骤1:给数据编连续时间序号t sales_with_seq AS ( SELECT year, sales, ROW_NUMBER() OVER (ORDER BY year) AS t -- t=1对应1960,t=23对应1982 FROM retail_sales ), -- 步骤2:递归计算三次平滑值 smoothing_values AS ( -- 初始行(t=0,初始值=1960年零售额) SELECT 0 AS t, NULL AS year, NULL AS sales, (SELECT sales FROM sales_with_seq WHERE t=1) AS s1, (SELECT sales FROM sales_with_seq WHERE t=1) AS s2, (SELECT sales FROM sales_with_seq WHERE t=1) AS s3 UNION ALL -- 递推行(t≥1,逐期计算平滑值) SELECT sws.t, sws.year, sws.sales, ROUND(0.3 * sws.sales + 0.7 * sv.s1, 4) AS s1, -- 一次平滑 ROUND(0.3 * (0.3 * sws.sales + 0.7 * sv.s1) + 0.7 * sv.s2, 4) AS s2, -- 二次平滑 ROUND(0.3 * (0.3 * (0.3 * sws.sales + 0.7 * sv.s1) + 0.7 * sv.s2) + 0.7 * sv.s3, 4) AS s3 -- 三次平滑 FROM smoothing_values sv JOIN sales_with_seq sws ON sv.t + 1 = sws.t ), -- 步骤3:计算预测参数(取最后一期t=23的平滑值) forecast_params AS ( SELECT s1, s2, s3, ROUND(3*s1 - 3*s2 + s3, 4) AS a, ROUND((0.3 / (2 * POWER(0.7, 2))) * ((6 - 5*0.3)*s1 - 2*(5 - 4*0.3)*s2 + (4 - 3*0.3)*s3), 4) AS b, ROUND((POWER(0.3, 2) / (2 * POWER(0.7, 2))) * (s1 - 2*s2 + s3), 4) AS c FROM smoothing_values WHERE t = (SELECT MAX(t) FROM sales_with_seq) ) -- 步骤4:预测1983/1985年零售额 SELECT 1983 AS forecast_year, ROUND(a + b*1 + c*POWER(1,2), 4) AS forecast_sales FROM forecast_params UNION ALL SELECT 1985 AS forecast_year, ROUND(a + b*3 + c*POWER(3,2), 4) AS forecast_sales FROM forecast_params;

2.2 关键解析

  1. 数据编序:通过ROW_NUMBER()将年份转为连续索引t,解决“递推依赖”的时间基准问题;

  2. 递归逻辑

    1. 初始行(t=0):设定三次平滑的初始值均为1960年零售额;

    2. 递推行:通过JOIN关联“当前期t”与“前一期t-1”,代入公式计算当期平滑值;

  3. 预测参数:仅取最后一期(1982年,t=23)的平滑值计算a/b/c,避免冗余;

  4. 预测值:1983年对应步长m=1,1985年对应m=3,代入非线性预测公式。

三、解法二:非递归(LAG窗口函数)实现

对于不支持递归CTE的老版本数据库(如MySQL 5.x),可通过LAG窗口函数获取前一期平滑值,分步计算一次、二次、三次平滑值,核心思路是“分步拆解递推逻辑”。

3.1 完整代码

-- 1. 复用原始数据表(同解法一,省略创建/插入步骤) -- 2. 非递归计算平滑值并预测 WITH -- 步骤1:数据编序 sales_with_seq AS ( SELECT year, sales, ROW_NUMBER() OVER (ORDER BY year) AS t FROM retail_sales ), -- 步骤2:计算一次平滑值s1 s1_calc AS ( SELECT t, year, sales, CASE WHEN t = 1 THEN sales -- 第一行初始值 ELSE ROUND(0.3 * sales + 0.7 * LAG(s1) OVER (ORDER BY t), 4) END AS s1 FROM ( SELECT t, year, sales, CAST(NULL AS DECIMAL(10,4)) AS s1 FROM sales_with_seq ) tmp ), -- 步骤3:基于s1计算二次平滑值s2 s2_calc AS ( SELECT t, year, sales, s1, CASE WHEN t = 1 THEN s1 -- 第一行初始值 ELSE ROUND(0.3 * s1 + 0.7 * LAG(s2) OVER (ORDER BY t), 4) END AS s2 FROM ( SELECT t, year, sales, s1, CAST(NULL AS DECIMAL(10,4)) AS s2 FROM s1_calc ) tmp ), -- 步骤4:基于s2计算三次平滑值s3 s3_calc AS ( SELECT t, year, sales, s1, s2, CASE WHEN t = 1 THEN s2 -- 第一行初始值 ELSE ROUND(0.3 * s2 + 0.7 * LAG(s3) OVER (ORDER BY t), 4) END AS s3 FROM ( SELECT t, year, sales, s1, s2, CAST(NULL AS DECIMAL(10,4)) AS s3 FROM s2_calc ) tmp ), -- 步骤5:计算预测参数 forecast_params AS ( SELECT s1, s2, s3, ROUND(3*s1 - 3*s2 + s3, 4) AS a, ROUND((0.3 / (2 * POWER(0.7, 2))) * ((6 - 5*0.3)*s1 - 2*(5 - 4*0.3)*s2 + (4 - 3*0.3)*s3), 4) AS b, ROUND((POWER(0.3, 2) / (2 * POWER(0.7, 2))) * (s1 - 2*s2 + s3), 4) AS c FROM s3_calc WHERE t = (SELECT MAX(t) FROM sales_with_seq) ) -- 步骤6:预测结果 SELECT 1983 AS forecast_year, ROUND(a + b*1 + c*POWER(1,2), 4) AS forecast_sales FROM forecast_params UNION ALL SELECT 1985 AS forecast_year, ROUND(a + b*3 + c*POWER(3,2), 4) AS forecast_sales FROM forecast_params;

3.2 关键解析

  1. 分步计算:将三次平滑拆分为三个CTE,先算一次平滑,再基于一次结果算二次,最后算三次,逻辑更直观;

  2. LAG函数:通过LAG(s1) OVER (ORDER BY t)获取前一期的一次平滑值,替代递归的“前一期关联”;

  3. 初始值处理:每一级平滑的第一行直接取初始值,后续行通过LAG递推,与递归解法保持一致。

四、两种解法对比

维度递归CTE解法非递归(LAG)解法
适配数据库MySQL 8.0+/PostgreSQL/PGMySQL 5.7+/PostgreSQL/PG(支持LAG)
代码简洁性代码更紧凑,一步完成递推代码分步拆解,步骤更多
可读性递推逻辑集中,适合熟悉递归的开发者分步清晰,新手更容易理解
调试难度需整体调试递归逻辑可单独查看每一级平滑值,易调试
性能数据量小时无差异,大数据量略优数据量小时无差异,步骤多但无性能损耗
适用场景支持递归的新版本数据库老版本数据库(无递归CTE)

五、实战注意事项

  1. 平滑系数α调整:α越小,平滑效果越强(更依赖历史数据);α越大,对近期数据越敏感。可通过“误差最小化”(如RMSE)调整α值;

  2. 异常数据处理:本文1972/1975年数据明显异常,实际应用中需先清洗(如修正笔误、剔除异常值);

  3. 预测步长:三次指数平滑适合短期预测(m≤5),步长过大会导致预测误差显著增加;

  4. 结果验证:两种解法的预测结果完全一致,可互相验证正确性。

六、总结

本文以“社会商品零售额预测”为例,实现了三次指数平滑法的两种SQL解法:递归CTE适合新版本数据库,代码紧凑;非递归(LAG)解法适配性更广,逻辑更直观。两种解法均遵循“初始值设定→逐期递推平滑值→计算预测参数→推导预测值”的核心流程,可直接复用至销量、产值等时间序列预测场景。

在实际应用中,可根据数据库版本选择解法,并结合业务场景调整平滑系数、清洗异常数据,以提升预测准确性。SQL作为数据处理的核心工具,直接实现时间序列算法可最大化利用数据库的存储与计算能力,减少数据迁移成本,是数据分析工程师的必备技能。

往期精彩

SQL进阶技巧:车辆班次问题分析_sql进阶技巧:车辆班次问题分析-CSDN博客

SQL 进阶技巧:断点重分组应用求连续段的最后一个数及每段的个数【拼多多面试题】_hql面试题46【拼多多面试题】-CSDN博客

SQL腾讯面试真题:玩家战败场次中点位占领统计问题-CSDN博客

面试提问:SQL 查询无数据时如何强制返回一行 0 | 通用兜底方案全解析_sql查询不到数据返回默认值-CSDN博客

SQL面试题:计算订单转化率和复购率(阿里数据分析一面)_sql计算复购率-CSDN博客

面试提问:数据开发中如何通过指标拆解来指导SQL编写?(附拆解模板)_根据指标维度来生成sql-CSDN博客

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/30 19:18:40

django基于python的农村医疗健康管理系统的设计与实现

目录农村医疗健康管理系统的设计与实现摘要关于博主开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式!农村医疗健康管理系统的设计与实现摘要 随着信息技术的快速发展,农村地区的医…

作者头像 李华
网站建设 2026/4/18 15:46:15

学霸同款8个AI论文平台,本科生轻松搞定毕业论文!

学霸同款8个AI论文平台,本科生轻松搞定毕业论文! AI 工具如何助力论文写作? 在当今学术研究日益复杂的背景下,越来越多的本科生开始借助 AI 工具来提升论文写作效率。这些工具不仅能帮助学生快速生成内容,还能有效降…

作者头像 李华
网站建设 2026/4/30 14:46:41

AI Agent在风险管理中的应用

AI Agent在风险管理中的应用关键词:AI Agent、风险管理、智能决策、自动化、风险评估摘要:本文深入探讨了AI Agent在风险管理领域的应用。首先介绍了相关背景,包括目的、预期读者等内容。接着阐述了AI Agent和风险管理的核心概念及联系&#…

作者头像 李华
网站建设 2026/4/28 20:59:58

Java--打印流

基本介绍在整个IO包中,打印流是输出信息做方便的类,主要包含字节打印流(PrintStream)和字符打印流(PrintWriter)。打印流提供了非常方便的打印功能,可以打印任何的数据类型,例如:小数、整数、字符串等等代码说明PrintS…

作者头像 李华
网站建设 2026/4/17 19:25:54

软件架构:业务与数据分离 + 三层独立扩展架构设计

「业务与数据分离 接入层、应用层、数据层独立扩展」是高可用、高弹性、松耦合的主流企业级软件架构核心设计思想,也是微服务 / 分布式架构的基础原则,这种架构能完美解决业务迭代快、数据量激增、流量波动大、扩容成本高的核心痛点,所有设计…

作者头像 李华