MySQL 5.7+ 支持 JSON_EXTRACT() 但仅返回单个 JSON 值,无法展开数组;真正摊开嵌套数组需用 MySQL 8.0.4+ 的 JSON_TABLE 配合 LATERAL JOIN,并注意 JSON_VALID 校验、字符集和生成列索引优化。

JSON_EXTRACT在MySQL中根本不存在
MySQL 5.7+ 原生支持的是 JSON_EXTRACT() 函数,但注意:它不是你想象中那个能直接展开数组、返回多行的“万能解析器”。它的行为非常明确——只返回一个 JSON 类型的值(比如字符串、数字、对象或数组),且结果仍包裹在双引号或方括号里。常见错误是写成 JSON_EXTRACT(json_col, '$.items[*].name') 后直接拿去 WHERE 或 GROUP BY,结果报错或逻辑错乱,因为返回的是 ["a","b"] 这样的 JSON 字符串,不是可枚举的行集。
真正能“摊开”嵌套数组的是JSON_TABLE
MySQL 8.0.4+ 引入了 JSON_TABLE,这才是处理多层嵌套、尤其是带数组结构的正解。它把一段 JSON 当作虚拟表来 JOIN,天然支持路径映射、类型转换和层级展开。
- 必须用
LATERAL关键字配合JOIN,否则无法引用上游表的 JSON 字段 - 路径表达式里不能用
[*]通配符直接写在最外层;要写成COLUMNS (name TEXT PATH '$.name')这种显式列定义 - 嵌套数组需用嵌套的
JSON_TABLE,例如先展开$.shops,再对每个shop的products字段再套一层JSON_TABLE
示例:从 page_data 中提取所有商品标题
SELECT jt1.shop_id, jt2.title FROM t, JSON_TABLE(page_data, '$.shops[*]' COLUMNS ( shop_id STRING PATH '$.shop_id', products JSON PATH '$.products' )) AS jt1, JSON_TABLE(jt1.products, '$[*]' COLUMNS ( title STRING PATH '$.title' )) AS jt2;
别忽略JSON_VALID和字符集问题
生产环境中,JSON 字段常混入非法字符(如未转义的换行、控制符)或编码不一致(UTF-8 vs GBK),导致 JSON_TABLE 直接报错退出,整条 SQL 失败。必须前置校验:
- 用
JSON_VALID(json_col)过滤掉脏数据,避免中断执行 - 确保字段声明为
JSON类型,而非TEXT或VARCHAR;后者即使内容合法,JSON_TABLE也可能因隐式转换失败 - 导入时若用
LOAD DATA INFILE,记得加CHARACTER SET utf8mb4
性能陷阱:别在WHERE里反复调用JSON函数
像 WHERE JSON_EXTRACT(data, '$.user.id') = '123' 这种写法,每行都会触发一次 JSON 解析,且无法走索引。更糟的是,如果同时写多个 JSON_EXTRACT,解析次数翻倍。
- 正确做法:提前用生成列(generated column)+ 索引固化常用路径,例如
ALTER TABLE t ADD user_id BIGINT AS (JSON_EXTRACT(data, '$.user.id')) STORED,再给user_id加索引 - 临时分析场景可用
CTE预解析一次,避免重复调用 -
JSON_CONTAINS和JSON_OVERLAPS在匹配数组时比多次JSON_EXTRACT更高效
复杂嵌套真正难的不是语法,而是路径是否完整覆盖所有分支、空数组/空对象是否被显式处理、以及生成列索引是否真正生效——这些地方一漏,查出来就是静默丢数。


















