sql server用string_agg、mysql用group_concat,二者不可混用;string_agg必须配合group by使用,分隔符须为常量,null默认被跳过,排序必须显式声明within group (order by),否则结果顺序不确定。

SQL分组查询中字符串聚合,核心就两件事:选对函数、防住坑。SQL Server 用 STRING_AGG,MySQL 用 GROUP_CONCAT,不能混用,也不能裸写。
SQL Server 必须用 STRING_AGG 配合 GROUP BY
它不是普通函数,是聚合函数,不能脱离分组单独出现。写成 SELECT STRING_AGG(name, ',') 会直接报错。
-
STRING_AGG第二个参数(分隔符)必须是常量,比如','或变量,**不能是列名**——否则报Msg 9836 - 默认跳过
NULL,整组全NULL就返回NULL;需要占位得提前用ISNULL(name, 'N/A') - **不显式写
WITHIN GROUP (ORDER BY ...),结果顺序不确定**,尤其在并行执行计划下,前后两次查询可能顺序不同 - 结果类型是
varchar(max)或nvarchar(max),超 2GB 会截断并报错String or binary data would be truncated
MySQL 的 GROUP_CONCAT 默认长度只有 1024
这是最隐蔽的坑:超长部分静默丢弃,不报错,你只会发现“怎么少了一半数据?”
- 查当前限制:
SELECT @@group_concat_max_len - 临时调高(当前会话):
SET SESSION group_concat_max_len = 1000000 - 永久生效要改
my.cnf,加group_concat_max_len = 1000000并重启 MySQL - 别无脑设最大值
4294967295,内存开销会上升,按业务最长拼接需求留 20% 余量即可
大小写、空格、排序规则影响分组结果
字符串分组不像数字那么“干净”,'ABC' 和 'abc' 在大小写敏感排序规则下就是两组。
- 想忽略大小写,统一用
LOWER(col)或UPPER(col)再分组 - 前后空格会导致分组分裂,
TRIM(col)是安全做法 - 跨库迁移时注意排序规则(
COLLATE),比如Latin1_General_CI_AS和utf8mb4_0900_as_cs行为不同 - 索引对
TRIM(LOWER(col))这类表达式无效,若高频使用,考虑加计算列并建索引
别指望 STRING_AGG 或 GROUP_CONCAT 去重或条件聚合
它们原生不支持 DISTINCT 或 CASE WHEN 直接嵌套——这不是 bug,是设计如此。
- 要去重?MySQL 加
DISTINCT关键字:GROUP_CONCAT(DISTINCT name) - SQL Server 没
DISTINCT支持,得靠子查询或 CTE 先去重:STRING_AGG(name, ',') WITHIN GROUP (ORDER BY name)前套一层SELECT DISTINCT ... FROM ... - 要条件拼接(比如只拼
status = 'active'的名字)?必须先过滤,不能把CASE往里塞 - 特殊字符不转义:
STRING_AGG和GROUP_CONCAT都原样拼,不会变成 <code><,前端展示时自己处理
真正麻烦的不是语法,而是分组前的数据清洗和分组后的长度/排序控制——这两步漏掉一个,线上就出不可复现的问题。











