MySQL 8.0+需用JSON_TABLE配合REPLACE构造合法JSON拆分逗号字符串,PostgreSQL用string_to_array+UNNEST更稳健,SQL Server的STRING_SPLIT()顺序不可靠且NULL输入返回空集,所有方案均需TRIM清洗空格并处理空值。

MySQL 8.0+ 用 JSON_TABLE 拆标签再 GROUP BY
JSON_TABLE 是唯一能原生把逗号分隔字符串转成行集的方案,但必须手动构造合法 JSON。常见错误是漏掉双引号或没转义内部引号,导致报错 Invalid JSON text。
- 假设字段
tag_list值为"news,tech,ai",先用REPLACE插入引号:CONCAT('["', REPLACE(tag_list, ',', '","'), '"]') - 再传给
JSON_TABLE:JSON_TABLE(CONCAT(...), '$[*]' COLUMNS (tag TEXT PATH '$')) -
JOIN后才能GROUP BY jt.tag;直接在SELECT中写jt.tag会报列不存在 - 若原始字段含空格或空字符串(如
"a,,b"),REPLACE会生成["a","","b"],JSON_TABLE仍会返回空字符串行,需额外加WHERE jt.tag != ''
PostgreSQL 用 string_to_array + UNNEST 最省心
string_to_array() 和 UNNEST() 组合天然支持数组语义,不用绕 JSON,性能更稳。
- 基础写法:
UNNEST(string_to_array(tag_list, ',')) AS tag,但若tag_list为空或全空格,UNNEST返回空结果集,该行直接消失 - 要保留主表所有行(包括无标签的),必须用
LEFT JOIN LATERAL,且NULLIF(..., ARRAY[''])过滤掉空数组 -
COALESCE(t.tag, 'none')可统一空标签为占位符,避免NULL在GROUP BY中被合并成一行
SQL Server 的 STRING_SPLIT() 顺序不可靠
STRING_SPLIT() 看似简单,但返回结果**不保证原始顺序**,且无序号列——如果业务依赖“第一个标签为主分类”,直接 GROUP BY 会丢失上下文。
- 不能依赖
ORDER BY value恢复顺序,因为输入是字符串,不是有序序列 - 若需保留位置信息,得用
STRING_AGG配合子查询反向验证,或提前在应用层拆分后存为规范结构 - 更隐蔽的坑:
STRING_SPLIT(NULL, ',')返回空集,不是单行NULL,导致JOIN时整行丢失,务必用LEFT JOIN+ISNULL或CASE补空
聚合前别跳过空值和脏数据清洗
所有方案都默认把"a, b ,c" 当作三个标签,但实际常含空格、重复、大小写混用。
-
TRIM()必须套在string_to_array()或REPLACE()外层,否则" a "和"a"会被视为不同标签 -
DISTINCT在GROUP BY前不起作用,要去重得用子查询或窗口函数过滤 - 如果标签有层级(如
"category:tech,sub:llm"),硬拆会破坏语义,此时应优先改表结构,而不是在 SQL 里硬解析
真正麻烦的从来不是拆分动作本身,而是拆完之后,谁来保证每个 "tag" 的语义一致、拼写统一、非空有效。

















