LAST_VALUE() 默认返回当前行值,因其窗口帧为ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW;需显式指定ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING并配合匹配语义的ORDER BY(如时间降序)才能获取分组真正末值。
LAST_VALUE() 能补空值,但默认行为几乎总是错的——必须显式写 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING,否则它只看“当前行及之前”,根本拿不到真正的“最后值”。
Oracle 默认窗口帧是 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW。这意味着每行只在自己和前面的行里找“最后一个值”,结果就是 LAST_VALUE(col) 基本等于 col 本身——尤其当 ORDER BY 是升序时,当前行就是“当前范围内最后一个”。
IGNORE NULLS + 正确帧: LAST_VALUE(col IGNORE NULLS) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING,且 ORDER BY 要匹配语义(如按 create_time DESC 才能拿到“最新”)LAST_VALUE 列看起来“有值”,但逻辑完全不可靠典型需求:某列存在 NULL 或 0,希望用最近一个非空值覆盖它(类似 Excel 的“向下填充”)。关键不是函数本身,而是组合方式。
NULLIF(col, 0) 把 0 当作 NULL 处理(如果业务中 0 表示缺失)LAST_VALUE(... IGNORE NULLS),帧必须是 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW(这是默认帧,可省略,但建议显式写出以明确意图)NVL(..., 0) 或 COALESCE(..., 'N/A') 处理首行无前值的情况NVL(LAST_VALUE(NULLIF(amount, 0) IGNORE NULLS) OVER (ORDER BY seq_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), 0)
这不是取整行,而是取某字段(如 status、update_time)在分组中的末尾值。容易踩坑的是 ORDER BY 方向与业务语义不一致。
order_id 下“最后更新时间”,ORDER BY update_time DESC + ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
ORDER BY id DESC,而不是 ASC——DESC 才能让最大 ID 排在窗口“最后”位置ORDER BY 字段有重复值(如多个记录同为 2025-01-01),LAST_VALUE() 仍可能返回任意一个,不具备确定性;此时更稳的做法是用 ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ... DESC) = 1 先定位行,再关联取值IGNORE NULLS 不是语法糖,它直接改变计算逻辑——尤其在填充类场景中,没它就毫无意义。
IGNORE NULLS:跳过所有 NULL,只在非空值中找“最后”那个;适合补空、继承有效值RESPECT NULLS(默认):把 NULL 当成合法值参与排序和定位;结果常是 NULL,除非你真需要“最后一个位置上的值,不管是不是空”IGNORE NULLS,但 Hive 或旧版 Oracle 可能不支持,需用 LAG() + COALESCE 替代LAST_VALUE(col) IGNORE NULLS —— IGNORE NULLS 必须紧跟在表达式后、OVER 前,即 LAST_VALUE(col IGNORE NULLS) OVER (...)
真正难的从来不是写对函数名,而是想清楚“最后”到底指什么——是时间上最新?ID 上最大?还是顺序上最靠后?这个语义必须由 ORDER BY 和窗口帧共同锁定,缺一不可。