JSON_EXTRACT返回NULL主因是路径错误:需以$开头,普通key不加引号(如$.name),特殊字符key必须双引号(如$."first-name"),数组用方括号,且源字段须为合法JSON。

JSON_EXTRACT 提取值时为什么总返回 NULL
不是字段没数据,而是路径写错了——MySQL 的 JSON 路径语法严格区分引号和层级结构,$.name 和 $."name" 在含特殊字符的 key 里才等价,普通 key 不加引号反而容易被解析失败。
- 确保路径以
$开头,嵌套用点号($.user.address.city),数组用方括号($.tags[0]) - key 含空格、短横线或数字开头时,必须用双引号包裹:
$."first-name"、$."[0]" - 如果字段本身是
NULL或不是合法 JSON,JSON_EXTRACT一律返回NULL;先用JSON_VALID()检查:SELECT JSON_VALID(json_col) FROM t;
- 别直接在 WHERE 里用
JSON_EXTRACT做等值判断——它返回的是带引号的字符串(如"admin"),要配合JSON_UNQUOTE或用->>操作符
用 -> 和 ->> 区分「带引号」和「去引号」结果
-> 是 JSON_EXTRACT 的快捷写法,返回 JSON 类型值(带双引号);->> 是 JSON_UNQUOTE(JSON_EXTRACT(...)) 的缩写,返回纯字符串或数字。选错会导致比较失败或隐式类型转换异常。
- WHERE 条件里匹配字符串,优先用
->>:WHERE data->>"$.role" = 'editor'
- 需要拼接 JSON 或继续嵌套提取时,用
->:SELECT JSON_EXTRACT(data->"$.config", "$.timeout")
-
->>对非字符串类型(如布尔、null、数字)也会“去引号”,但 MySQL 会自动转成对应类型;不过NULL值经->>后仍是NULL,不是字符串"null"
JSON_SET/JSON_REPLACE/JSON_INSERT 容易混淆的语义差异
三个函数都改 JSON 字段,但行为边界很关键:不存在的路径,JSON_SET 强制创建,JSON_REPLACE 完全忽略,JSON_INSERT 只在路径不存在时写入。
- 想“有则更新、无则新增”,用
JSON_SET:UPDATE t SET json_col = JSON_SET(json_col, "$.status", "done");
- 只更新已有字段,避免意外新增字段,用
JSON_REPLACE - 只初始化默认值(比如首次设置
$.created_at),用JSON_INSERT - 所有操作都不支持通配符或正则路径;数组追加得用
JSON_ARRAY_APPEND,不是JSON_SET
JSON_CONTAINS 性能差,别在大表 WHERE 里直接用
JSON_CONTAINS 无法走索引,每次都要完整解析 JSON 字符串,数据量一过万行,查询就明显变慢。它适合小结果集过滤,不适合主查询条件。
- 真要按 JSON 内字段高频查询,把关键字段冗余为普通列(如
status VARCHAR(20)),并建索引 - MySQL 5.7+ 支持生成列 + 函数索引:
ALTER TABLE t ADD COLUMN status VARCHAR(20) AS (json_col->>"$.status");<br>CREATE INDEX idx_status ON t(status);
-
JSON_CONTAINS_PATH比JSON_CONTAINS轻量,只检查路径是否存在,不解析值,适合快速判空
JSON 函数看着灵活,但每个都卡在「字符串解析」这一步——没有真正的 JSON 类型索引,也没有原生数组运算。越依赖深层嵌套,越容易掉进性能和可读性的坑里。


















