LAST_VALUE默认仅在当前行及之前查找,结果常等于当前列值;需显式指定ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING才能获取分组末尾值,且ORDER BY方向决定“最后”含义,重复排序字段须加唯一列,取整行应改用ROW_NUMBER()。

LAST_VALUE 默认只看“当前行及之前”
直接写 LAST_VALUE(col) OVER (ORDER BY ts),结果几乎总是等于 col 本身——不是 bug,是标准定义。因为默认窗口帧是 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,即每行只在自己和前面的行里找“最后一个”,当前行自然就是那个“最后”。
要取整组末尾值,必须显式拉满窗口范围
想让 LAST_VALUE 真正拿到分组内排序后的物理末条记录对应值,得强制它看到全部数据:
-
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING是唯一可靠方式,覆盖整个分区 - 仅靠
PARTITION BY不够,不加这句帧定义,LAST_VALUE仍按行逐段截断计算 - 某些旧版 SQL Server(2012–2014)对带
UNBOUNDED FOLLOWING的LAST_VALUE有处理缺陷,建议升级或改用ROW_NUMBER()
ORDER BY 方向决定“最后”是谁,容易反直觉
窗口帧只是“范围”,真正哪一行算“最后”,全由 ORDER BY 定义:
- 按时间升序
ORDER BY created_at+ 全局帧 → “最后” = 最大时间那行 - 按时间降序
ORDER BY created_at DESC+ 全局帧 → “最后” = 最小时间那行(即最早创建) - 排序字段有重复时,务必补唯一列:如
ORDER BY created_at DESC, id DESC,否则结果不可控
取整行数据时,LAST_VALUE 本质不适用
LAST_VALUE 只能返回单个表达式的值,无法保证多个字段来自同一原始记录:
- 写
LAST_VALUE(id)、LAST_VALUE(status)、LAST_VALUE(amount)各自独立计算,若created_at有重复,三者可能拼出一条根本不存在的“幻影记录” - 真正需要最新整行,应优先用
ROW_NUMBER() OVER (PARTITION BY x ORDER BY ts DESC, id DESC) = 1过滤 -
FIRST_VALUE配合降序更少出错,但仍是单字段;它不解决“取整行”问题
ROWS BETWEEN ...,就等于没告诉数据库“你要在哪一段里找最后”,它只能按默认规则——从开头到当前行——去算,而这个规则和业务常说的“组内最后一条”基本不是一回事。

















