lead必须配合partition by user_id和order by业务时间字段(如created_at),否则会跨用户取值导致错乱;推荐写法为lead(event_type) over (partition by user_id order by created_at, id),并注意null处理、排序稳定性及数据库语法差异。

LEAD必须配PARTITION BY user_id + ORDER BY时间字段
不加PARTITION BY user_id,LEAD会跨用户取“下一条”,结果完全错乱。比如用户A的最后一条订单后面紧跟着用户B的第一条,LEAD就直接把B的订单当成A的“下一次行为”。
ORDER BY只用id也不可靠——ID可能被删、重用或非严格递增;必须用业务时间字段,如created_at或event_time。
- 推荐写法:
LEAD(event_type) OVER (PARTITION BY user_id ORDER BY created_at, id) -
created_at有NULL?先过滤或用COALESCE(created_at, '1970-01-01')兜底 - 同一秒多事件?加
id作二级排序,避免数据库随机取值
LEAD返回NULL不是bug,是语义结果
最后一行天然没有“下一行”,LEAD返回NULL完全正常。但很多人误以为数据丢了,其实是分区边界问题。
- 某用户只有一条行为记录 → 全部
LEAD结果都是NULL - WHERE条件写在窗口函数外层(如
WHERE event_type = 'login'),会导致排序基于全表,但过滤后“下一条”已被删掉 → LEAD仍尝试取,结果为NULL - 需要默认值?加第三个参数:
LEAD(event_type, 1, 'no_next')
计算行为间隔时,数据库语法差异极大
LEAD只负责取值,算差值得你自己写,且不同库写法完全不同。
- MySQL:
LEAD(created_at) OVER (...) - created_at→ 直接得整数天 - PostgreSQL:
LEAD(created_at) OVER (...) - created_at→ 返回interval,要转成天数得EXTRACT(day FROM ...) - SQL Server:必须用
DATEDIFF(second, created_at, LEAD(created_at) OVER (...)),单位得显式指定 - 含时分秒?MySQL会截断,PostgreSQL保留小数天 → 后续求平均值可能偏差明显
别指望LEAD做预测,它只做提取
LEAD不是机器学习模型,不会拟合趋势、外推时间点或判断概率。它只是从已有记录里机械地取下一行值。
- 写
LEAD(created_at, 2)≠ “预测第二次行为”,只是取该用户第三条记录的时间 - 想看间隔变化?得叠加聚合,比如
AVG(LEAD(...) - created_at)按用户分组,再统计分布 - 要做留存分析?先用LEAD标记“有没有下一次活跃”,再用
CASE WHEN next_event IS NOT NULL统计比例
最容易被忽略的是:LEAD的结果依赖排序稳定性。一旦ORDER BY字段存在重复且没加二级键,每次执行结果可能不同——这在报表或ETL中会埋下静默错误。











