lag() 获取上一条订单时间需配合 over(partition by user_id order by user_id, order_time),否则跨用户计算错误;首单返回null,需coalesce兜底;时间相减语法因数据库而异,须先确认类型并统一转换。

用 LAG() 获取上一条订单时间
核心是拿到当前行的前一行 order_time,LAG() 是最直接的方式。它属于窗口函数,必须配合 OVER 子句使用,且要注意排序逻辑——如果没按用户和时间双重排序,间隔会算错。
- 必须写
ORDER BY user_id, order_time,否则跨用户取前一行,结果完全不可信 -
LAG(order_time, 1)中的1是默认值,可省略;但显式写出更易读 - 首条订单没有“上一条”,
LAG()返回NULL,后续做减法时需处理(比如用COALESCE填默认值)
用时间减法算出分钟/秒级间隔
不同数据库对时间相减的支持差异大:PostgreSQL 支持直接 order_time - prev_time 得到 interval;MySQL 需用 TIMESTAMPDIFF(MINUTE, prev_time, order_time);SQL Server 要用 DATEDIFF(minute, prev_time, order_time)。别硬套语法,先确认你用的是哪个库。
- PostgreSQL 示例:
EXTRACT(EPOCH FROM (order_time - LAG(order_time) OVER (PARTITION BY user_id ORDER BY order_time))) / 60→ 得到分钟数(含小数) - MySQL 必须指定单位,
TIMESTAMPDIFF(SECOND, ...)比MINUTE更精确,避免整数截断 - 如果字段是字符串(如
'2023-05-01 14:22:03'),先转成时间类型再算,否则可能报错或返回 0
按用户分组计算,避免跨用户混算
漏写 PARTITION BY user_id 是高频错误。不加这句,LAG() 会在全表范围内按 order_time 排序取前一行,A 用户的最后一单可能接在 B 用户的第一单后面,间隔变成几小时甚至几天,毫无业务意义。
-
PARTITION BY user_id确保每个用户独立计算“相邻”关系 - 如果还要看“同一地址下的相邻单”,就改成
PARTITION BY address_id,逻辑一致 - 注意:
PARTITION BY和ORDER BY的字段不能矛盾,比如按user_id分组却按全局时间排序,会导致组内顺序错乱
空值与边界情况要主动兜底
第一条订单的间隔天然为 NULL,但报表或下游程序常要求填 0 或 -1。另外,如果两条订单时间相同(比如批量导入),间隔为 0,是否合理得看业务——有些场景要过滤掉,有些要保留并标记。
- 用
COALESCE(TIMESTAMPDIFF(...), 0)把首单间隔设为 0 - 加
WHERE order_time > LAG(order_time) OVER (...)可排除时间倒挂脏数据(但慎用,可能误删) - 如果想统计“首次下单后 24 小时内复购率”,得先用子查询或 CTE 把间隔列算出来,再在外层加条件过滤,不能在窗口函数里直接
WHERE
实际跑起来最常卡在排序和分组没对齐,或者时间类型没统一。先 SELECT user_id, order_time, LAG(order_time) OVER (PARTITION BY user_id ORDER BY order_time) 查一眼中间结果,比直接套公式靠谱得多。











