json_extract 返回 null 最常见原因是路径错误:必须以 $ 开头、字段名用双引号包裹;源字段为 null 或非有效 json、数组越界、嵌套路径中断也会导致 null。

JSON_EXTRACT 为什么返回 NULL?
最常见的问题是 JSON_EXTRACT 返回 NULL,不是因为 JSON 格式错,而是路径写错了。MySQL 要求 JSON 路径必须以 $ 开头,且字段名必须用双引号包裹(哪怕它看起来像合法标识符)。比如:$.name 正确,$.name 在某些情况下也“碰巧”能用,但 .name 或 $name 一定失败。
另外,如果源字段本身是 NULL 或不是有效 JSON(比如存的是字符串 "{name: 'a'}" 而没加引号),JSON_EXTRACT 也会返回 NULL —— 它不自动尝试解析字符串内容。
- 检查原始字段是否为
JSON类型,或至少通过JSON_VALID(col)验证 - 路径中含空格、连字符、数字开头的 key,必须写成
$."user-id"或$."1st_login" - 数组索引从 0 开始,
$[0]是第一个元素,$[99]超出范围也返回NULL,不会报错
提取字符串值时要不要加双引号?
JSON_EXTRACT 总是返回带引号的 JSON 字符串(即类型为 json),比如 JSON_EXTRACT('{"a": "hello"}', '$.a') 返回 "hello"(含双引号)。如果你要直接参与字符串比较或拼接,得用 JSON_UNQUOTE() 去掉外层引号。
常见误操作:写 WHERE JSON_EXTRACT(data, '$.status') = 'active' —— 实际对比的是 "active" 和 active,永远不等。
Miller (mlr) 是一个命令行工具,用于查询、整形和重新格式化名称索引数据,如 CSV、TSV、JSON 和 JSON Lines。它将 awk、sed、cut、join 和 sort 的功能整合到一个专为结构化数据处理而构建的单一工具中。
- 正确写法:
WHERE JSON_UNQUOTE(JSON_EXTRACT(data, '$.status')) = 'active' - 更简洁写法:
WHERE data->>'$.status' = 'active'(->>是JSON_EXTRACT + JSON_UNQUOTE的语法糖) - 注意:
->(不带 >)返回带引号的 JSON,->>返回去引号的字符串
嵌套对象和数组怎么安全取值?
深层嵌套如 {"user": {"profile": {"age": 25}}},路径写 $.user.profile.age 没问题;但如果中间某层缺失(比如 profile 不存在),整个表达式就返回 NULL,没法区分是字段不存在还是值就是 NULL。
想判断是否存在某个路径,别依赖返回值是否为 NULL,改用 JSON_CONTAINS_PATH(data, 'one', '$.user.profile.age') —— 它只管路径存不存在,不管值是什么。
- 取数组第一个非空字符串:
JSON_UNQUOTE(JSON_EXTRACT(data, '$.tags[0]')),但若tags是空数组或根本不存在,结果仍是NULL - 安全取数组长度:
JSON_LENGTH(data, '$.tags'),比先JSON_EXTRACT再CHAR_LENGTH可靠得多 - 遍历数组要用
JSON_TABLE(8.0+),JSON_EXTRACT本身不支持循环
性能和索引要注意什么?
JSON_EXTRACT 本身不走索引,哪怕你对整个 JSON 字段建了 GENERATED COLUMN 并为其加索引,也得确保生成列定义和查询条件完全一致,否则优化器可能放弃使用。
例如:定义了 status VARCHAR(20) GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(data, '$.status'))) STORED,并对其加索引。那么查询必须写成 WHERE status = 'active',而不是 WHERE JSON_EXTRACT(data, '$.status') = '"active"'。
- 避免在
WHERE中直接对大 JSON 字段反复调用JSON_EXTRACT,尤其在 JOIN 或子查询里 - 用
JSON_EXTRACT提取后做ORDER BY,会触发 filesort,不如提前存到生成列 - MySQL 5.7 不支持函数索引,8.0+ 才能对表达式建索引,版本不匹配时容易白忙活
-> 和 ->> 的返回类型,还有在没建生成列的情况下硬扛 JSON 字段做高频查询。










