mysql 8.0.17+ 推荐用 json_table 拆分字符串:先 replace 构造合法 json 数组,再通过 columns 显式定义列名与类型;5.7 只能依赖数字辅助表或 substring_index 嵌套,存在性能差、长度受限及空值处理缺陷。

MySQL 8.0+ 直接用 JSON_TABLE 拆分字符串(推荐)
MySQL 8.0.17+ 原生支持将逗号等分隔符分隔的字符串转成行集合,核心是先转成 JSON 数组,再用 JSON_TABLE 展开。前提是字符串格式规整(如 'a,b,c'),且不含嵌套或特殊转义。
实操建议:
- 用
REPLACE把分隔符(如逗号)替换成",",再前后加[和]构造成合法 JSON 字符串 -
JSON_TABLE的COLUMNS子句必须显式声明列名和类型,比如col VARCHAR(100) PATH '$' - 若原始字符串含空值(如
'a,,c'),JSON_TABLE会跳过空项;需保留空项得先用TRIM+ 条件替换预处理
SELECT jt.col
FROM (SELECT REPLACE(CONCAT('["', REPLACE('a,b,c', ',', '","'), '"]'), '""', '"null"') AS json_str) t,
JSON_TABLE(t.json_str, '$[*]' COLUMNS (col VARCHAR(100) PATH '$')) AS jt;
MySQL 5.7 或低版本只能靠递归 CTE 模拟(有严格限制)
MySQL 5.7 不支持 JSON_TABLE,也不支持标准递归 CTE(直到 8.0.1 才引入),所以实际可行方案只剩「数字辅助表」或「自连接生成序号」——但性能差、长度受限、代码冗长。
常见错误现象:
- 用
SUBSTRING_INDEX嵌套多次取值,但硬编码层级(如只写到第 5 层),超出就漏数据 - 依赖
information_schema.columns生成序号,结果因权限或表结构变化而失败 - 没处理分隔符连续出现的情况(如
'a,,b'),导致空行被忽略或错位
最小可用示例(适用于已知最大拆分项数 ≤10):
SELECT TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX('a,b,c', ',', nums.n), ',', -1)) AS col
FROM (SELECT 1 n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) nums
WHERE nums.n <h3>用存储过程动态拆分(适合复杂逻辑但运维成本高)</h3><p>当需要保留原始顺序、处理引号包裹字段(如 <code>'"a,b",c'</code>)、或做后置清洗时,存储过程更可控。但它无法直接用于 SELECT 子查询,只能先写入临时表再 JOIN。</p><p>关键注意事项:</p>
-
WHILE循环中必须用LOCATE+SUBSTRING精确切分,避免SUBSTRING_INDEX在含分隔符的字段内误切 - 临时表需显式
DROP TEMPORARY TABLE,否则并发调用会冲突 - 没有异常捕获机制,字符串为空或无分隔符时容易陷入死循环
别踩这个坑:GROUP_CONCAT 是聚合,不是拆分
新手常误以为 GROUP_CONCAT 能逆向拆分,其实它只做合并。反过来用会导致语义混乱、执行计划失效,甚至触发 group_concat_max_len 截断而不报错。
真正要拆分时,永远优先检查 MySQL 版本 —— 8.0.17+ 就别手写循环;低于该版本,接受「长度可控 + 预设上限」的前提,再选数字表方案。动态场景一律走应用层拆分更稳。











