json_extract路径必须用单引号包裹,如'$.user.name';数组越界返回null;提取字符串需json_unquote去引号;where中直接使用会导致索引失效,建议用生成列+索引优化。

JSON_EXTRACT 路径语法必须用双引号包裹字符串字面量
MySQL 的 JSON_EXTRACT 不接受裸字符串路径,比如 $.user.name 直接写会报错 ERROR 3141 (22032): Invalid JSON text in argument 1 to function json_extract。路径参数必须是字符串常量或变量,且需用单引号包裹整个路径,内部字段名无需额外转义(除非含特殊字符)。
正确写法示例:
SELECT JSON_EXTRACT('{"user": {"name": "Alice", "tags": ["admin", "dev"]}}', '$.user.name');
常见错误包括:
- 漏掉外层单引号:写成
JSON_EXTRACT(..., $.user.name)→ 语法错误 - 路径中误用双引号:写成
'"$."user".name"'→ JSON 解析失败 - 对数字索引不加方括号:想取第一个 tag 写成
$.user.tags.0→ 无效,必须写$.user.tags[0]
处理数组元素时,下标越界返回 NULL 而非报错
MySQL 的 JSON 路径支持数组访问,但行为和直觉略有差异:当指定的数组下标超出范围(如 [5] 但数组只有 3 个元素),JSON_EXTRACT 静默返回 NULL,不会中断查询。这在 JOIN 或 WHERE 条件中容易引发隐性逻辑漏洞。
例如:
SELECT JSON_EXTRACT('{"items": [{"id": 1}, {"id": 2}]}', '$.items[5].id'); -- 返回 NULL,不是报错
若你依赖该值做非空判断,需显式检查:
- 用
IS NOT NULL判断提取结果是否存在 - 用
JSON_LENGTH()先确认数组长度再取值,避免假阴性 - 对关键业务字段,建议配合
COALESCE(..., 'default')提供兜底值
提取结果带双引号?用 JSON_UNQUOTE 去除引号包装
JSON_EXTRACT 返回的是 JSON 类型值,对字符串、数字、布尔等原始类型仍保留 JSON 编码格式。这意味着提取字符串会得到带双引号的结果:"Alice" 而非 Alice;提取布尔值得 true(JSON true)而非 MySQL 的 1/0。
若后续要参与字符串拼接、LIKE 匹配或插入到非 JSON 字段,必须用 JSON_UNQUOTE:
SELECT JSON_UNQUOTE(JSON_EXTRACT('{"name": "Alice"}', '$.name')); -- 返回 Alice(无引号)
注意:
-
JSON_UNQUOTE(NULL)仍为NULL,安全 - 对数字类型提取后直接参与计算(如
+ 1),MySQL 会自动隐式转换,此时可不加JSON_UNQUOTE;但显式调用更可靠 - 别混淆
JSON_EXTRACT(json_col, '$.field') = '"value"'和= 'value'—— 前者是 JSON 字符串比较,后者是文本比较,结果不同
WHERE 子句中用 JSON_EXTRACT 要警惕索引失效
直接在 WHERE 中写 JSON_EXTRACT(meta, '$.status') = 'active' 会导致全表扫描,即使 meta 列上有索引。MySQL 无法对函数结果使用普通 B+Tree 索引。
可行方案有:
- 改用生成列 + 索引:
ALTER TABLE orders ADD status VARCHAR(20) AS (JSON_UNQUOTE(JSON_EXTRACT(meta, '$.status'))) STORED;
然后CREATE INDEX idx_status ON orders(status); - MySQL 5.7+ 支持虚拟列索引,但 STORED 列更稳妥(尤其涉及复制或备份时)
- 避免在大表上频繁执行
JSON_CONTAINS或嵌套多层JSON_EXTRACT的 WHERE 条件
深层嵌套(如 $.a.b.c.d.e)不仅慢,还可能因 JSON 解析开销放大延迟,实际线上应尽量扁平化存储或预计算关键字段。











