You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

分组聚合时仅用用户最新值的PostgreSQL优雅SQL实现问询

优雅解决PostgreSQL用户最新记录的灵活聚合需求

嘿,这个需求用PostgreSQL的窗口函数就能轻松搞定,比你说的复杂关联写法清爽太多,而且灵活性拉满!

核心思路:先锁定每个用户的最新记录

首先我们用ROW_NUMBER()窗口函数给每个用户的记录按时间倒序排号,最新的那条记录会被标记为1。这一步是固定的,不管后续怎么聚合,只要拿到每个用户的最新记录,剩下的操作就非常灵活了。

灵活聚合的实现代码

第一步:获取每个用户的最新记录(通用部分)

我们可以用CTE(公共表表达式)把这部分逻辑抽出来,方便后续复用:

WITH user_latest_records AS (
    SELECT
        user_id,
        vals,
        created_at,
        -- 按用户分组,按创建时间倒序排,最新的记录行号为1
        ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS record_rank
    FROM your_table_name
)

第二步:按需选择聚合方式

场景1:按月份分组,计算最新记录的vals总和

只需要在CTE基础上筛选出最新记录,再按月份分组求和:

WITH user_latest_records AS (
    SELECT
        user_id,
        vals,
        created_at,
        ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS record_rank
    FROM your_table_name
)
SELECT
    DATE_TRUNC('month', created_at) AS month, -- 把时间截断到月份
    SUM(vals) AS total_vals
FROM user_latest_records
WHERE record_rank = 1 -- 只保留每个用户的最新记录
GROUP BY month
ORDER BY month;

场景2:按user_id分组,查看每个用户最新记录的vals(或其他聚合)

如果要切换成按用户分组,只需要修改外层的GROUP BY和聚合逻辑,完全不用动CTE部分:

WITH user_latest_records AS (
    SELECT
        user_id,
        vals,
        created_at,
        ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS record_rank
    FROM your_table_name
)
SELECT
    user_id,
    vals AS latest_val, -- 直接取最新记录的vals
    created_at AS latest_record_time
FROM user_latest_records
WHERE record_rank = 1
ORDER BY user_id;

额外优化:处理同一用户多条“最新”记录的情况

如果你的业务中存在同一个用户在同一时间有多条记录(比如created_at完全相同),并且这些记录都需要被纳入计算,那可以把ROW_NUMBER()换成RANK(),这样所有并列最新的记录都会被标记为1,不会被过滤掉:

-- 替换CTE里的行号函数
RANK() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS record_rank

这种写法的好处就是逻辑分层清晰,取最新记录的逻辑和后续聚合逻辑完全解耦,想换聚合方式只需要改外层查询,非常灵活,而且可读性比复杂的关联写法高太多!

内容的提问来源于stack exchange,提问作者eljusticiero67

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:47:18