LEAD函数必须指定column参数,配合OVER子句中的ORDER BY和PARTITION BY才能正确获取下一行数据;其基本形式为LEAD(column, offset, default) OVER (PARTITION BY group_col ORDER BY sort_col),offset默认1,default默认NULL,缺一不可。

LEAD函数的基本用法和必要参数
LEAD函数必须指定至少一个参数:LEAD(column, offset, default),其中column是你要“向前看”的字段(比如用户行为时间、事件类型),offset默认为1,表示取下一行的值;default在越界时返回(比如最后一行没有下一行,就填NULL或你指定的值)。不写default会导致漏斗中末尾环节丢失匹配。
关键点在于:LEAD本身不定义“路径”,它只是把下一行的数据拉到当前行——所以必须配合ORDER BY和PARTITION BY才能按用户+时间对齐行为序列。
常见错误现象:LEAD(event_type) OVER (ORDER BY event_time) —— 缺少PARTITION BY user_id,结果把不同用户的点击混在一起,转化路径完全错乱。
构造用户级有序行为序列是前提
漏斗追踪本质是“同一个用户,在时间上连续发生的若干事件”。所以第一步永远是确保数据按user_id分组、按event_time排序。否则LEAD拉出来的下一行,根本不是该用户下一步动作。
实操建议:
- 先用
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY event_time)验证排序是否稳定(比如有相同时间戳时,是否引入二级排序字段如event_id) - 如果原始
event_time精度只有秒级,且单用户一秒内有多次行为,务必补上唯一序号字段,否则LEAD取值顺序不可控 -
PARTITION BY user_id不能省略,哪怕表里只有一用户——SQL引擎不会自动推断业务语义
多步漏斗需嵌套多个LEAD调用
要追踪“浏览→加购→下单→支付”四步路径,就得用三次LEAD把后续三步都拉到当前行:
SELECT
user_id,
event_type AS step1,
LEAD(event_type, 1) OVER (PARTITION BY user_id ORDER BY event_time) AS step2,
LEAD(event_type, 2) OVER (PARTITION BY user_id ORDER BY event_time) AS step3,
LEAD(event_type, 3) OVER (PARTITION BY user_id ORDER BY event_time) AS step4
FROM events
WHERE event_type IN ('view', 'add_to_cart', 'order', 'pay')
注意:LEAD(..., 2)不是“第二步”,而是“当前行之后第2行的事件”,所以它对应的是第三步。容易混淆的点在于:step1是当前行,step2是下一行,step3是下下一行……别数错偏移量。
性能提示:每个LEAD都会触发一次窗口计算,4步就是4次全量排序。若数据量大,优先考虑用LAG反向建模(从支付往回找),或改用ARRAY_AGG聚合后用脚本处理。
过滤有效路径时小心NULL和跨天行为
直接WHERE step1 = 'view' AND step2 = 'add_to_cart' AND step3 = 'order'会漏掉两种情况:一是用户加购后隔天再下单(时间断层但仍是有效路径),二是LEAD返回NULL被WHERE过滤掉(比如某用户只做了浏览,后面没行为,整行被丢弃)。
更稳妥的做法:
- 先保留所有
step1 = 'view'的行,再用CASE WHEN标记各环节是否达成,避免用AND连等丢数据 - 加入时间窗口判断,例如
LEAD(event_time, 1) - event_time ,防止把半年前的加购误认为本次浏览的下一步 - 确认数据库对
INTERVAL的支持:PostgreSQL用INTERVAL '7 days',MySQL要用DATE_ADD(event_time, INTERVAL 7 DAY),语法差异直接影响条件生效
真正难的不是写对LEAD,而是定义清楚“什么是有效转化”——时间跨度、事件必选性、是否允许跳步,这些业务规则得先落地,函数只是执行工具。










