mysql用group_concat()合并多行数据需配合group by使用,否则整表压成一行;默认长度限制1024字节易截断,须用set session group_concat_max_len调整;支持distinct去重、order by排序、separator指定分隔符,null值自动跳过但全null时返回null,应配合coalesce或ifnull处理。

MySQL 用 GROUP_CONCAT() 合并多行
MySQL 没有标准 SQL 的 STRING_AGG(),必须用 GROUP_CONCAT()。它默认只拼接非 NULL 值,且长度上限是 1024 字符(超长会被截断)。
常见错误是直接写 GROUP_CONCAT(name) 却没加 GROUP BY,结果整张表被压成一行,但分组逻辑错乱。正确做法是明确按业务主键或关联字段分组。
- 调整长度限制:执行
SET SESSION group_concat_max_len = 10000;(会话级生效) - 去重拼接:用
GROUP_CONCAT(DISTINCT name) - 指定分隔符和排序:用
GROUP_CONCAT(name ORDER BY id SEPARATOR '; ') - 空值处理:
COALESCE(name, '')可防止某列为 NULL 导致整段拼接结果为 NULL
PostgreSQL 用 STRING_AGG() 处理 NULL 和排序
STRING_AGG() 是 PostgreSQL 的标准方案,但默认遇到 NULL 就返回 NULL——这点和 MySQL 的 GROUP_CONCAT() 行为不同,容易漏掉数据。
典型误用是写 STRING_AGG(name, ',') 却没过滤或转换 NULL。实际中建议始终包裹一层 COALESCE() 或配合 FILTER 子句。
- 安全拼接:用
STRING_AGG(COALESCE(name, ''), ',') - 跳过 NULL 行:用
STRING_AGG(name, ',' ORDER BY id) FILTER (WHERE name IS NOT NULL) - 注意:ORDER BY 必须写在
STRING_AGG()内部,不能放在外层查询的 ORDER BY 里
SQL Server 用 STRING_AGG()(2017+)或 FOR XML(旧版本)
SQL Server 2017 起支持 STRING_AGG(),但早期版本只能靠 FOR XML PATH('') + STUFF() 组合实现,写法绕、易出错。
用 STRING_AGG() 时要注意:它不自动去重,也不忽略 NULL;而 FOR XML 方案对特殊字符(如 &、)会自动转义,导致结果含 <code>& 这类编码,需额外处理。
- 新版本推荐:
STRING_AGG(ISNULL(name, ''), ',') WITHIN GROUP (ORDER BY id) - 旧版本兼容写法:
STUFF((SELECT ',' + ISNULL(name, '') FROM t2 WHERE t2.group_id = t1.id FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') - 别忘了
TYPE和.value(),否则可能返回 XML 标签包裹的字符串
跨数据库可移植的简化思路
真要写一次 SQL 跑多个库?基本不可行。各数据库函数名、参数顺序、NULL 处理、排序语法全都不一致,硬套只会埋坑。
更现实的做法是:在应用层做聚合(比如查出多行后用 Python 的 ', '.join() 或 JS 的 arr.join(', ')),尤其当数据量不大、或需要复杂清洗逻辑时,反而更可控、更易测。
强行用 SQL 合并,最容易被忽略的是字符集和排序规则影响——比如 MySQL 中 utf8mb4 和 utf8 混用可能导致截断,PostgreSQL 中 collation 不一致会让 ORDER BY 结果意外错乱。










