mysql中实现多行拼接成一行最直接的方法是使用group_concat函数,需配合group by使用,支持distinct去重、order by排序、separator自定义分隔符,但默认group_concat_max_len为1024字节,超长会被静默截断。

MySQL用GROUP_CONCAT把多行拼成一行
MySQL里最直接的办法就是GROUP_CONCAT,它专为这事设计。默认用逗号分隔,但能自定义分隔符、排序、去重和长度限制。
常见错误是没加GROUP BY导致整张表被强行聚合,或者忽略group_concat_max_len限制(默认1024字节),超长内容被无声截断。
- 用
ORDER BY子句控制拼接顺序,比如GROUP_CONCAT(name ORDER BY id) - 用
SEPARATOR指定分隔符:GROUP_CONCAT(name SEPARATOR ' | ') - 去重加
DISTINCT:GROUP_CONCAT(DISTINCT city) - 改长度限制要同时设会话级变量:
SET SESSION group_concat_max_len = 1000000
PostgreSQL用STRING_AGG替代
PostgreSQL没有GROUP_CONCAT,对应的是STRING_AGG函数,语法更严格,必须显式指定分隔符,且不支持去重(得靠子查询或DISTINCT ON)。
容易漏掉ORDER BY子句——STRING_AGG不保证顺序,不写就可能每次结果不同。
- 基础用法:
STRING_AGG(name, ', '),第二个参数是分隔符,不可省略 - 带排序:
STRING_AGG(name, ', ' ORDER BY created_at) - 去重需套一层:
STRING_AGG(DISTINCT name, ', ')(9.6+ 支持) - 空值会被跳过,不需要额外
WHERE name IS NOT NULL
SQL Server的STRING_AGG从2017才支持
SQL Server 2017+ 引入了STRING_AGG,行为接近PostgreSQL,但早期版本(2016及之前)只能靠FOR XML或CLR函数硬凑,非常容易出错。
典型坑是:旧版本误用STRING_AGG报错Invalid object name 'STRING_AGG';新版本忘了写WITHIN GROUP (ORDER BY ...)导致排序不可控。
- 必须写排序子句:
STRING_AGG(name, ', ') WITHIN GROUP (ORDER BY id) - 不支持
DISTINCT,要去重得先GROUP BY或用子查询 - 空字符串不会被过滤,但
NULL会被忽略(和PG一致) - 如果目标列是
TEXT类型,得先CAST成VARCHAR(MAX),否则报错
跨数据库兼容写法几乎不存在
别指望一条SQL在MySQL、PG、SQL Server里都跑通。GROUP_CONCAT、STRING_AGG、LISTAGG(Oracle)三者语法差异大,参数位置、是否强制排序、空值处理都不一样。
真要写通用逻辑,要么在应用层拼接(查出多行再join),要么用ORM的聚合方法(如Django的StringAgg、SQLAlchemy的func.string_agg),避免SQL硬编码。
最容易被忽略的是字符集和排序规则影响——比如MySQL里utf8mb4字段拼接后出现乱码,其实是连接层或客户端没同步设置好character_set_results。










