跳到主要内容

last_value:窗口内最后一个值

速查结论

last_value(expr[, isIgnoreNull]) 是 Spark SQL 窗口函数中用于获取窗口内最后一个值的函数。注意:不指定 IGNORE NULLS 且不明确设置窗口边界 ROWS BETWEEN 时,返回结果可能与预期不符,默认窗口边界会随当前行收缩。

语法

last_value(expr[, isIgnoreNull]) OVER (
[PARTITION BY ...]
[ORDER BY ...]
[ROWS BETWEEN ... AND ...]
)

参数说明

参数说明
expr待取值的表达式或列名
isIgnoreNull可选,布尔值。为 true 时跳过 NULL 值,返回最后一个非 NULL 值。默认 false

返回值:窗口内 expr 的最后一个值。如果 isIgnoreNull 为 true 则跳过 NULL。

Since: 2.0.0

示例

基础用法

-- 无分区、无排序:全表视为一个窗口
SELECT last_value(col) FROM VALUES (10), (5), (20) AS tab(col);
-- 结果: 20

IGNORE NULLS — 跳过 NULL 值

-- 不忽略 NULL:最后一个值是 NULL,返回 NULL
SELECT last_value(col) FROM VALUES (10), (5), (NULL) AS tab(col);
-- 结果: NULL

-- 忽略 NULL:跳过 NULL,返回 5
SELECT last_value(col, true) FROM VALUES (10), (5), (NULL) AS tab(col);
-- 结果: 5

带 ORDER BY 的窗口

-- 按时间排序,取每个用户最后一次订单金额
SELECT
user_id,
order_time,
last_value(amount) OVER (
PARTITION BY user_id
ORDER BY order_time
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS last_amount
FROM orders;

不指定窗口边界的陷阱

-- 错误写法:默认窗口边界随当前行收缩,每行的 last_value 可能不同
SELECT
val,
last_value(val) OVER (ORDER BY ts) AS last_val
FROM t;
-- 结果可能不符合预期:默认 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

-- 正确写法:明确指定全窗口范围
SELECT
val,
last_value(val) OVER (
ORDER BY ts
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS last_val
FROM t;

last_value vs first_value vs nth_value 对比

函数返回内容典型场景
last_value(expr)窗口内最后一个值获取最终状态、最新值
first_value(expr)窗口内第一个值获取初始状态、最早值
nth_value(expr, n)窗口内第 n 个值获取指定位置的值(如第2名)
lag(expr, n)当前行往前 n 行环比分析、行间差值
SELECT
user_id,
order_time,
first_value(amount) OVER (PARTITION BY user_id ORDER BY order_time) AS first_amount,
last_value(amount) OVER (
PARTITION BY user_id ORDER BY order_time
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS last_amount
FROM orders;

常见报错与避坑指南

忘记指定窗口边界导致结果不对

这是 last_value 最常见的错误。默认窗口边界为 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,导致 last_value 取到的其实是当前行的值。

-- 错误写法:每行的 last_value 等于当前行
SELECT
name,
score,
last_value(score) OVER (ORDER BY score) AS last_score
FROM students;
-- 结果:每行的 last_score = 当前行的 score

-- 正确写法:明确指定窗口边界
SELECT
name,
score,
last_value(score) OVER (
ORDER BY score
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS last_score
FROM students;
-- 结果:每行的 last_score = 全表最后一个 score

NULL 值污染结果

不设置 isIgnoreNull 时,如果窗口内最后一个值是 NULL,last_value 就返回 NULL。这在 GSC 数据中表现突出——last_value 搜索变体有多个,用户大概率是遇到了 NULL 返回问题。

-- 错误写法:最后一个值可能是 NULL
SELECT last_value(amount) OVER (ORDER BY date) FROM sales;
-- amount 最后一行是 NULL → 返回 NULL

-- 正确写法:忽略 NULL
SELECT last_value(amount, true) OVER (
ORDER BY date
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) FROM sales;

非确定性行为

该函数是非确定性的:结果取决于行的顺序,shuffle 之后行顺序可能变化,导致结果不稳定。生产环境中务必在 OVER 子句中使用 ORDER BY 保证确定性。

-- 风险写法:无 ORDER BY,shuffle 后结果不确定
SELECT last_value(col) OVER () FROM t;

-- 安全写法:明确排序
SELECT last_value(col) OVER (ORDER BY id) FROM t;
📱关注公众号

「数据仓库技术」文章同步更新,不错过每一篇干货

微信公众号二维码
💬加群交流

备注「数据仓库技术」加入社群,每日一道大厂SQL真题

交流微信二维码

你可能还想看