JSON_EXTRACT返回JSON类型值,故字符串带引号、数字为字符串形式;需用->>或JSON_UNQUOTE获取可用值,并配合JSON_VALID校验合法性、JSON_LENGTH判数组长度、JSON_TABLE展开数组(8.0.4+)。

JSON_EXTRACT 是最直接的解析入口,但实际使用中必须搭配路径表达式和类型处理才能拿到可用值。MySQL 5.7.8+ 原生支持 JSON 类型,不是所有“看起来像 JSON”的字符串都能用 JSON_EXTRACT 安全解析——只有真正被 MySQL 认证为 JSON 的字段(即声明为 JSON 类型、或经 CAST(... AS JSON) 转换过的)才具备路径查询能力。
为什么 JSON_EXTRACT(json_col, '$.key') 返回带引号的字符串?
JSON_EXTRACT 总是返回 JSON 类型结果,哪怕提取的是数字或布尔值。比如 JSON_EXTRACT('{"age": 25}', '$.age') 返回的是 "25"(字符串),不是整数 25。这会导致后续计算或比较出错:
- WHERE JSON_EXTRACT(data, '$.age') > 20 实际按字符串比较,"100" ORDER BY JSON_EXTRACT(data, '$.age') 排序结果不符合数值逻辑。
正确做法是用 ->> 操作符替代:data->>'$.age' 等价于 JSON_UNQUOTE(JSON_EXTRACT(data, '$.age')),直接返回无引号的标量值(字符串、数字、true/false/null),可参与数值运算和索引下推。
如何安全提取嵌套对象或数组中的字段?
路径表达式必须严格匹配结构,否则返回NULL(不报错,容易忽略):
- 对象字段用点号:data->>'$.address.city'
- 数组元素用方括号:data->>'$.tags[0]'(取第一个)、data->>'$.items[1].name'(取第二个 item 的 name)
- 数组长度不确定时,避免硬写索引;可用 JSON_LENGTH(data->'$.tags') 先判断
- 若路径可能不存在,JSON_CONTAINS_PATH(data, 'one', '$.optional_field') 可提前校验
常见错误:
- 写成
data->>'$address.city'(漏掉.),路径无效,返回NULL - 对 JSON 数组误用对象语法:
data->>'$.list.name'→ 应为data->>'$.list[0].name'或配合JSON_TABLE展开 - 字段名含特殊字符(如空格、短横线)必须用双引号包裹路径:
data->>'$."user-id"'
什么时候该用 JSON_TABLE 而不是 ->>?
当需要把 JSON 数组“炸开”成多行关系数据时,->> 无能为力,必须上 JSON_TABLE:
- 示例:一个订单记录里存了 {"items": [{"id":1,"qty":2},{"id":2,"qty":1}]},想查每项商品的 qty
- SELECT order_id, jt.id, jt.qty FROM orders, JSON_TABLE(items, '$.items[*]' COLUMNS (id INT PATH '$.id', qty INT PATH '$.qty')) AS jt;注意点:
-
JSON_TABLE是 MySQL 8.0.4+ 才支持,5.7 不可用 - 路径必须以
[*]结尾表示“对每个数组元素执行” -
COLUMNS中的PATH是相对于数组元素的子路径,不是整个 JSON 文档
真正麻烦的不是语法,而是 JSON 字段缺乏约束——同一个字段里可能存对象、数组、null、甚至根本不是 JSON(如果早期用 TEXT 存的)。上线前务必用 JSON_VALID() 批量检查存量数据,再决定是否加 GENERATED COLUMN + INDEX 优化高频查询路径。


















