string_agg是postgresql最可靠的多行字符串拼接函数,需严格遵循string_agg(expression, delimiter)参数顺序,支持order by排序、null处理及distinct去重,但须注意group by正确性、性能调优与类型兼容性。

STRING_AGG 是 PostgreSQL 里最直接、最可靠的多行字符串拼接方案,只要 GROUP BY 逻辑清晰,它基本不会出错。但参数顺序、分隔符空值处理、NULL 行行为这些细节,一不留神就导致结果意外截断或缺失。
STRING_AGG 的基本用法和参数顺序不能颠倒
函数签名是 STRING_AGG(expression, delimiter),第一个参数是待拼接的字段或表达式,第二个是分隔符 —— 这个顺序不能反。如果写成 STRING_AGG(',', col),PostgreSQL 会报错 function string_agg(unknown, text) does not exist,因为类型推导失败。
常见场景是聚合用户标签、订单商品名等:
SELECT user_id, STRING_AGG(tag, ', ') AS tags FROM user_tags GROUP BY user_id;
- 分隔符可以是任意字符串,包括空字符串
''(此时无间隔拼接) - 如果
delimiter为NULL,整个结果变NULL,不是忽略分隔符 - 表达式支持
CASE WHEN或COALESCE,比如STRING_AGG(COALESCE(name, 'unnamed'), ';')
遇到 NULL 值时,默认被跳过,但需主动控制排序
STRING_AGG 默认忽略 NULL 值,这通常符合预期;但它不保证拼接顺序 —— 没有 ORDER BY 子句时,结果顺序由执行计划决定,可能每次查询都不一样。
PostgreSQL 18.4 官方 Ubuntu 安装包现已发布,这是目前最新的稳定版本。推荐通过官方 APT 仓库安装:先执行 sudo apt update 更新索引,再运行 sudo apt install postgresql-18 即可完成部署。新版本引入了异步 I/O 子系统,在顺序扫描与 VACUUM 场景下性能提升显著,同时支持 UUID v7 原生生成函数与虚拟生成列。
正确做法是在函数内显式加 ORDER BY:
SELECT category, STRING_AGG(product_name, ' | ' ORDER BY price DESC) AS top_products FROM products GROUP BY category;
-
ORDER BY必须写在括号内、分隔符之后,语法是STRING_AGG(expr, delim ORDER BY col) - 可多字段排序,如
ORDER BY status, created_at DESC - 如果排序字段含
NULL,默认排在最前;要统一置后,得写ORDER BY col NULLS LAST
GROUP BY 字段漏写或写错,会导致聚合范围错误
这是实际中最常踩的坑:想按用户合并标签,却忘了 GROUP BY user_id,或者误把 user_name 当主键用了(而实际存在重名),结果数据被意外合并。
- 检查
SELECT中所有非聚合字段是否都在GROUP BY列表中 - 避免用别名参与
GROUP BY(某些 PG 版本不支持),写成GROUP BY t.user_id而非GROUP BY uid - 若需去重后再拼接,必须先子查询或 CTE 去重:
STRING_AGG(DISTINCT tag, ', ')是合法的,但只对单字段有效;复杂去重要靠DISTINCT ON或窗口函数预处理
大数据量下性能敏感,注意排序和内存开销
当某组要拼接上千行字符串时,STRING_AGG 会把全部值加载进内存排序再连接,可能触发 work_mem 不足,出现“could not resize shared memory segment”类警告甚至慢查询。
- 确认
work_mem设置合理(如 16MB~64MB),尤其在 OLAP 场景 - 避免在未过滤的宽表上直接聚合,先用
WHERE缩小范围 - 如果只是取前 N 项拼接,优先用窗口函数限制行数,而不是拼完再
SUBSTRING截断
真正麻烦的是跨字符集拼接(比如 bytea + text 混合)、超长字符串截断边界,以及和 jsonb_agg 混用时的类型隐式转换——这些不在基础用法范围内,但一旦出现,错误信息往往不直接指向 STRING_AGG 本身。










