
本文介绍如何使用 ROW_NUMBER() 配合整数除法对数据进行逻辑分组,再通过 STRING_AGG() 实现每组最多 4 个值的字符串聚合,避免单行结果过长,提升可读性与下游处理兼容性。
本文介绍如何使用 `row_number()` 配合整数除法对数据进行逻辑分组,再通过 `string_agg()` 实现每组最多 4 个值的字符串聚合,避免单行结果过长,提升可读性与下游处理兼容性。
在实际业务中,常需将多条记录(如样本编号)聚合成逗号分隔的字符串。但若直接使用 STRING_AGG() 配合 GROUP BY,可能产生超长单行结果(如含数十个编号),不利于展示、解析或前端渲染。PostgreSQL 提供了灵活的窗口函数能力,可轻松实现「按固定数量切分再聚合」的需求。
核心思路是:先为原始记录按指定顺序编号,再基于编号计算逻辑分组 ID,最后按该 ID 分组聚合。关键在于分组 ID 的构造——利用整数除法向下取整特性:(row_number() - 1) / N 可将连续行每 N 条划为一组(从 0 开始编号)。
以下为完整示例(假设源表为 rec_agg,字段为 sample_no):
PostgreSQL 18.4 官方 Ubuntu 安装包现已发布,这是目前最新的稳定版本。推荐通过官方 APT 仓库安装:先执行 sudo apt update 更新索引,再运行 sudo apt install postgresql-18 即可完成部署。新版本引入了异步 I/O 子系统,在顺序扫描与 VACUUM 场景下性能提升显著,同时支持 UUID v7 原生生成函数与虚拟生成列。
WITH mk_grp AS (
SELECT
sample_no,
((ROW_NUMBER() OVER (ORDER BY sample_no)) - 1) / 4 AS grp
FROM rec_agg
)
SELECT STRING_AGG(sample_no, ' ,') AS sampl_nos
FROM mk_grp
GROUP BY grp
ORDER BY grp;
✅ 输出效果(每组最多 4 个编号,按字典序分组):
┌────────────────────────┐ │ sampl_nos │ ├────────────────────────┤ │ 0001 ,0002 ,0003 ,0004 │ │ 0005 ,0006 ,0007 ,0008 │ │ 0009 ,0010 ,0011 │ └────────────────────────┘
⚠️ 注意事项:
- ORDER BY 子句在 ROW_NUMBER() 中至关重要——它决定了编号顺序,进而影响分组边界。请根据业务需求选择稳定排序字段(如时间戳、主键或 sample_no 自身);
- / 4 使用的是整数除法(PostgreSQL 中两整数相除自动截断小数),确保 (n-1)/4 在 [0,1,2,3] → 0,[4,5,6,7] → 1,依此类推;
- 若需自定义分组大小(如每组 5 条),仅需将 / 4 改为 / 5;
- 结果默认无序,建议显式添加 ORDER BY grp 保证输出顺序与分组逻辑一致;
- 此方案完全在数据库层完成,无需应用层拆分,性能高效且易于复用。
该方法简洁、可靠,适用于报表导出、批量任务分片、API 分页聚合等典型场景。










