SQL中计算5日均线必须用AVG()窗口函数并显式指定ORDER BY trade_date和ROWS BETWEEN 4 PRECEDING AND CURRENT ROW,否则返回全量均值;SQLite不支持ROWS,需改用自连接或预补日期;NULL值会被自动忽略,可能掩盖数据问题,建议检查并预处理;trade_date字段须建索引以保障性能。

SQL里用AVG()算5日均线必须加ORDER BY和ROWS BETWEEN
不指定窗口排序和范围,AVG()会返回全量均值,不是你要的“最近5个交易日”的移动平均。核心是把AVG()变成窗口函数,且必须显式定义时间顺序和行数边界。
-
ORDER BY trade_date不能省——股票数据按日期排序才有“前5日”意义,否则窗口方向不确定 -
ROWS BETWEEN 4 PRECEDING AND CURRENT ROW才是5日:当前行 + 往前4行 = 5行。写成5 PRECEDING就错了,那会包含6行 - 如果日期有缺失(比如节假日休市),用
trade_date排序仍能保证“交易日数量”准确;但若想按自然日回溯,就得先生成连续日期再左连接补空,那是另一层问题
PostgreSQL/MySQL 8.0+/SQL Server 都支持,但SQLite不支持ROWS BETWEEN
SQLite的AVG()窗口函数只支持RANGE(基于值范围),不支持ROWS(基于行数),所以无法严格按“5个交易日”计算。遇到SQLite必须换思路:
- 用自连接或子查询手动关联最近5条记录,性能差但可行
- 提前在应用层或ETL中补全日期、填充
NULL值,再用RANGE BETWEEN INTERVAL '4 days' PRECEDING AND CURRENT ROW(仅PostgreSQL支持) - 直接导出到支持
ROWS的引擎里算,别硬扛
遇到NULL收盘价时AVG()自动跳过,但可能掩盖数据质量问题
窗口AVG()默认忽略NULL,比如某只股票第3日close_price为NULL,那第5日的均线实际只算4个有效值。这看起来“合理”,但容易掩盖上游数据异常:
- 检查原始数据中
close_price IS NULL的比例,高频出现说明数据源有问题 - 若需强制5日参与(比如用前值填充),得先用
COALESCE(close_price, LAG(close_price) OVER (ORDER BY trade_date))预处理 - 注意
AVG()结果类型:整数列可能被截断,建议显式转DECIMAL(10,2)或FLOAT
性能关键点:trade_date字段必须建索引,且避免在窗口函数里套复杂表达式
数据库优化器对窗口函数的执行计划依赖排序字段的索引。没索引时,每行都要重新扫描前5行,O(n²)复杂度。
- 确保
CREATE INDEX idx_stock_date ON stock_prices (symbol, trade_date);——复合索引兼顾多股票场景 - 别写
AVG(COALESCE(close_price * 1.0, 0))这种带运算的表达式,先算好列再进窗口 - 如果只查某只股票,
WHERE symbol = '600519'必须放在窗口计算之前,否则全表扫完才过滤
窗口函数的“5日”是硬性行数约束,不是软性时间逻辑。哪怕某天数据延迟入库,只要它排在第5位,就会被纳入——这点和K线软件里的实现一致,但也意味着你要对数据落库顺序有掌控力。

















