sql中字符串拼接需按数据库选用对应聚合函数:sql server 2017+用string_agg(),mysql用group_concat(),postgresql也用string_agg();均需在函数内用order by排序,且注意null处理与分隔符设置。

SQL 中 GROUP BY 本身不拼接字符串,它只分组;真正拼接靠聚合函数,不同数据库用的函数完全不同,选错会报错或返回乱码。
SQL Server 2017+ 必须用 STRING_AGG(),别碰 FOR XML PATH
旧写法 STUFF() + FOR XML PATH('') 看似通用,但实际埋雷:
- 遇到
&、、<code>>会自动转义成&、、<code>>,结果不是你写的字符串,而是 XML 实体编码 - 排序必须嵌套子查询 +
ORDER BY,稍一漏就乱序,且无法在外部再控制顺序 - 只要分组内任意
employee_name是NULL,整个拼接结果可能变NULL(取决于上下文),而STRING_AGG()默认跳过NULL
正确写法只要一行:
SELECT dept, STRING_AGG(emp_name, ', ') WITHIN GROUP (ORDER BY hire_date) AS staff_list FROM employees GROUP BY dept;
MySQL 用 GROUP_CONCAT(),注意分隔符和去重逻辑
这个函数支持原生去重和排序,但默认行为容易被忽略:
- 分隔符默认是英文逗号
,,不是中文顿号或空格,显式写SEPARATOR '; '更安全 -
DISTINCT要放在字段前,不是函数外:写成GROUP_CONCAT(DISTINCT cla),不是DISTINCT GROUP_CONCAT(cla) - 如果某组所有值都是
NULL,结果是NULL,不是空字符串;需要补COALESCE(GROUP_CONCAT(...), '')
常见组合:
SELECT id, name,
GROUP_CONCAT(cla ORDER BY num DESC SEPARATOR ' → ') AS course_path,
SUM(num) AS total_hours
FROM st
GROUP BY id, name;
PostgreSQL 同样用 STRING_AGG(),但支持 DISTINCT 直接去重
和 SQL Server 语法一致,但多一个实用特性:
-
STRING_AGG(DISTINCT tag, ', ')可直接去重,不用子查询或窗口函数 - 若字段含
NULL,它默认忽略;想保留可先用COALESCE(tag, 'N/A') - 性能上,单次扫描 + 内存聚合,比用
ARRAY_AGG() + ARRAY_TO_STRING()更轻量
注意:WITHIN GROUP 必须紧跟在括号后,不能写成 STRING_AGG(...) WITHIN GROUP (...) GROUP BY —— 顺序错就语法报错。
跨数据库兼容?别硬凑,按环境选函数
没有银弹。强行写“兼容版”往往导致语义错误或性能崩坏:
- 不要在 SQL Server 2019 上为“兼容 MySQL”而用
GROUP_CONCAT—— 它根本不存在,直接报错Invalid column name 'GROUP_CONCAT' - 不要在 PostgreSQL 里模拟
FOR XML,XML 函数既慢又难读,还容易引号逃逸出错 - 应用层拼接(如 Python 循环 join)看似灵活,但把分组逻辑移出数据库,丢失了索引利用和流式处理能力,大数据量时 IO 和内存双爆炸
真正要兼容的点,其实是字段类型对齐和空值处理策略 —— 比如统一用 COALESCE(x, '') 替代裸字段,比纠结函数名重要得多。
最常被忽略的是排序控制:STRING_AGG() 和 GROUP_CONCAT() 的 ORDER BY 子句,必须写在聚合函数内部,不是写在外部 SELECT 或 GROUP BY 之后;写错位置等于没写。










