LEAD是窗口函数,必须配合OVER子句及ORDER BY排序使用;基本形式为LEAD(column, offset, default),offset默认为1且须为正整数,default为越界时返回值。

LEAD函数的基本用法和必需参数
LEAD 是窗口函数,必须配合 OVER 子句使用,否则直接报错 Window function requires OVER clause。它默认取下一行的值,但不指定偏移量时,LEAD(column) 等价于 LEAD(column, 1),不是“自动推断”——省略第二个参数不会出错,但逻辑上仍按偏移 1 处理。
最简可用形式是:LEAD(value_column, offset, default_value) OVER (ORDER BY sort_column)。其中 offset 和 default_value 都可选,但 ORDER BY 在 OVER 中不可省略,否则结果无意义(行序未定义)。
-
value_column:要取值的列名,不能是表达式(如LEAD(a + b)会报错,需先计算再引用) -
offset必须是常量整数,不能是列名或变量(LEAD(x, n)中的n不支持动态值) -
default_value在越界时返回(比如最后一行调用LEAD),不提供则返回NULL
ORDER BY 决定“下一行”的实际含义
数据库没有天然的“行顺序”,LEAD 的“下一行”完全取决于 OVER 中的 ORDER BY。如果排序字段有重复值,且未加唯一性约束(如主键、时间戳),结果可能不稳定——同一语句多次执行,相同输入可能返回不同 LEAD 值。
例如按 status 排序后用 LEAD 查看下一个状态,若多条记录 status = 'pending',它们之间的相对顺序由优化器决定,LEAD 可能跳到任意一个“下一个 pending”,而非你预期的插入顺序。
- 安全做法:在
ORDER BY中加入唯一列,如ORDER BY created_at, id - 避免仅用
ORDER BY name这类高重复字段驱动LEAD - MySQL 8.0+、PostgreSQL、SQL Server 都遵循此规则;SQLite 3.25+ 支持,但旧版本不支持窗口函数
LEAD 与 LAG 混用时的常见陷阱
同一个 OVER 子句可以被多个窗口函数复用,但要注意:所有函数共享同一排序逻辑。如果写成 LEAD(val) OVER w, LAG(val) OVER w,其中 w AS (ORDER BY ts),那两者都基于 ts 排序——这没问题;但如果误写成 LEAD(val) OVER (ORDER BY a), LAG(val) OVER (ORDER BY b),就是两个独立窗口,性能差且易混淆。
- 别在单个 SELECT 中为同一列写多个不同
OVER,除非真需要不同排序视角 -
LEAD(x, 1)和LAG(x, 1)并非严格互逆:对第一行,LEAD返回第二行值,LAG返回NULL;对最后一行,LEAD返回NULL,LAG返回倒数第二行值 - 想对比“当前 vs 下一行”,只用
LEAD;想对比“当前 vs 上一行”,只用LAG;混用时务必确认业务是否真需双向参考
性能影响和替代方案考量
LEAD 是窗口函数,执行时需扫描并缓存整个分区数据(即使只取下一行),在大表 + 无索引 ORDER BY 字段时,I/O 和内存开销明显高于普通 JOIN。例如对千万级订单表按 user_id 分区后查“用户下次下单时间”,若 user_id 未建索引,ORDER BY user_id, created_at 可能触发临时文件排序。
- 当只需“下一条记录”的简单场景,且能保证物理顺序稳定(如自增 ID 有序插入),用
JOIN+id + 1可能更快,但前提是id连续无空缺 -
LEAD在分组内使用(PARTITION BY)时,分区键最好有索引,否则每个分区都要独立排序 - PostgreSQL 中
LEAD在带PARTITION BY时,若分区大小差异极大(如某用户有 10 万条记录,其余人均
真正难的不是写对语法,而是想清楚“下一行”在业务里到底指什么——是时间上的下一个事件?还是流水号递增的下一个?还是某个状态变更序列里的下一个?选错 ORDER BY 或忽略重复值,比函数写错更难排查。

















