lead和lag函数必须配合order by使用,否则结果无意义;其核心是按order by定义的行序获取相邻数据,而非自然时间,需用带时区的时间戳排序并处理重复日期、null值、交易日历偏差及性能优化。

LEAD 和 LAG 函数必须配合 ORDER BY 使用,否则结果无意义
在股票价格分析中,LEAD 和 LAG 的核心作用是获取相邻时间点的数据,比如“明天的收盘价”或“昨天的成交量”。但这两个函数本身不感知时间顺序——它们只按查询中 ORDER BY 定义的行序取值。如果漏写 ORDER BY,或者排序字段不是严格单调的时间戳(如用 date 但存在重复日期且未加二级排序),结果会错位甚至随机。
- 务必用带时区的
datetime或timestamp字段排序,避免仅用date - 若存在同一日多条行情(如分钟级数据),需补充
ORDER BY trade_time, id确保稳定排序 - PostgreSQL 和 SQL Server 支持
NULLS FIRST/LAST,但 MySQL 8.0 不支持,注意跨库兼容性
计算价格涨跌幅时,LAG 返回 NULL 会导致整个表达式为 NULL
直接写 ROUND((close - LAG(close) OVER (ORDER BY trade_time)) / LAG(close) OVER (ORDER BY trade_time) * 100, 2) 在首行会报除零或返回 NULL,因为 LAG(close) 对第一行返回 NULL,而任何数与 NULL 运算结果都是 NULL。
- 用
COALESCE(LAG(close) OVER (...), close)把首行的“前一日价格”补成本日价格,避免除零 - 更合理的做法是用
CASE WHEN LAG(close) OVER (...) IS NOT NULL THEN ... ELSE 0 END显式跳过首行计算 - 不要依赖
WHERE LAG(...) IS NOT NULL——窗口函数不能在WHERE中引用,得套一层子查询或 CTE
LEAD(…, 3) 并不等价于“三天后”,而是“当前行之后第 3 行”
股票市场有休市日,LEAD(close, 3) 取的是排序后的第 3 条记录,不是日历上的“3 天后”。如果数据里缺失某日行情(例如节假日没数据),LEAD(close, 3) 会跳到实际存在的第 3 条,可能对应 5 个自然日后。
- 真要对齐交易日,得先生成完整交易日历表,再 LEFT JOIN 补全缺失日期,再用
LAG/LEAD - 若只做技术指标(如 5 日均线),建议用
AVG(close) OVER (ORDER BY trade_time ROWS BETWEEN 4 PRECEDING AND CURRENT ROW),它按行数而非日期跨度计算 - MySQL 8.0+、PostgreSQL、SQL Server 都支持
ROWS滑动窗口;但旧版 MySQL 不支持,只能用自连接模拟
在高频行情中,窗口函数性能会明显下降
对每秒上千条 tick 数据执行 LAG(close) OVER (PARTITION BY symbol ORDER BY trade_time),若未建合适索引,扫描成本会随数据量线性增长。尤其当 PARTITION BY 字段基数高(如万只股票),每个分区都要单独排序。
- 复合索引必须包含
(symbol, trade_time),且trade_time在第二位,否则无法加速窗口排序 - 避免在窗口函数中嵌套复杂表达式,如
LAG(log(close))—— 先算好log_close列再窗口引用 - 实时看盘场景下,优先考虑应用层缓存前一行值,而不是每次查数据库跑
LAG
真实场景里最常被忽略的,是交易日历和物理行序之间的偏差——你看到的“昨日涨跌”,背后可能是数据库里两行之间隔了 72 小时,也可能只是 3 秒。窗口函数只认行序,不认日历。











