LAST_VALUE默认只返回当前行值,因其窗口帧为ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW;要获取分组内排序后的末值,须显式指定UNBOUNDED FOLLOWING,或更稳妥地用FIRST_VALUE配合降序排序。

LAST_VALUE 默认窗口帧只到 CURRENT ROW
LAST_VALUE 返回当前行,不是 bug,是 SQL 标准定义的行为:默认窗口帧为 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW。它只看“从分区开头到当前行(含)”这段数据,当前行自然就是这个范围里的“最后一个”。哪怕你写了 ORDER BY created_at DESC,只要没显式改帧,LAST_VALUE(status) 仍只在已扫过的行里找,结果几乎总等于本行 status。
显式指定 UNBOUNDED FOLLOWING 才能覆盖整组
要真正拿到分组内排序后的末值,必须手动补全窗口定义:
LAST_VALUE(col) OVER (PARTITION BY g ORDER BY t ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)- 仅写
ORDER BY或仅加PARTITION BY不够,缺了ROWS BETWEEN ...这一句,就还是当前行 - 某些引擎(如旧版 MySQL)不支持
UNBOUNDED FOLLOWING,此时应换用FIRST_VALUE+ 降序排序
用 FIRST_VALUE(DESC) 更安全、更少出错
多数人想取“最新一条”,本质是“按时间倒序后的第一条”。FIRST_VALUE(col) OVER (PARTITION BY g ORDER BY updated_at DESC) 天然匹配该语义,且默认帧就足够——不用额外写 UNBOUNDED FOLLOWING,也不依赖对 LAST_VALUE 帧规则的记忆。
- 排序字段重复时,务必加二级排序,例如:
ORDER BY updated_at DESC, id DESC -
FIRST_VALUE在 PostgreSQL、MySQL 8.0+、SQL Server、BigQuery 上行为一致 - 若字段可能为
NULL,建议显式写NULLS LAST(PostgreSQL)或避免NULL参与排序(MySQL)
LAST_VALUE 不能直接取整行,别硬套
LAST_VALUE 是逐列计算的:你写十个 LAST_VALUE(x)、LAST_VALUE(y),它们可能来自不同物理行——尤其当 ORDER BY 字段不唯一时。它解决不了“取最新订单的 id + amount + status”这种需求。
- 真正要取完整记录,优先用
ROW_NUMBER() OVER (PARTITION BY g ORDER BY t DESC, id DESC) AS rn,再WHERE rn = 1 - 用
LAST_VALUE只适合辅助场景,比如广播“每组最大时间”到所有行,再配合 JOIN 或 WHERE 匹配 - 大表上若
ORDER BY列无索引,OVER计算开销会陡增
ORDER BY,还强依赖帧定义;而“最后一条记录”这个业务目标,往往被误认为只需一个函数就能解决——实际上它常需要排序确定性、去重兜底、以及行级筛选三者配合。

















