JSON_EXTRACT返回带引号字符串,需用->操作符或JSON_UNQUOTE转裸值;多层路径越界返回NULL;NULL输入总得NULL,应先JSON_VALID校验;更新用JSON_REPLACE更安全;遍历数组需WHILE配合JSON_LENGTH和动态路径。

JSON_EXTRACT 用法和常见解析错误
MySQL 5.7+ 支持原生 JSON 类型,但 JSON_EXTRACT 返回的是带引号的字符串(如 "value"),不是裸值,直接参与比较或计算会出错。比如 JSON_EXTRACT(data, '$.age') > 18 在某些版本里返回 NULL —— 因为右边是整数,左边是 JSON 字符串,类型不匹配。
- 用
->操作符替代JSON_EXTRACT:它自动去引号,等价于JSON_UNQUOTE(JSON_EXTRACT(...)) - 需要提取多层嵌套时,路径必须严格合法,
'$.items[0].name'中索引越界不会报错,而是返回 NULL,容易掩盖逻辑缺陷 - 对 NULL 输入调用
JSON_EXTRACT总是返回 NULL,不抛异常,建议先用JSON_VALID()做前置校验
在存储过程中安全地更新 JSON 字段
直接用 SET json_col = JSON_SET(json_col, '$.status', 'done') 看似简单,但有三个隐性风险:字段本身为 NULL 时结果仍是 NULL;路径不存在时会创建新键,可能污染结构;并发写入时无锁保护,可能覆盖他人修改。
- 更新前加判断:
IF JSON_VALID(json_col) THEN ... END IF; - 用
JSON_REPLACE替代JSON_SET,它只更新已有路径,不新增字段 - 若需原子性更新(如计数器),避免先查后改,改用
JSON_SET(json_col, '$.count', COALESCE(JSON_EXTRACT(json_col, '$.count'), 0) + 1)
存储过程里遍历 JSON 数组的可行方案
MySQL 没有原生的 JSON 数组 for-each 循环,JSON_CONTAINS 或 JSON_SEARCH 都只能做查找,不能逐项处理。硬要遍历,得靠递归 CTE 或辅助数字表,但存储过程中无法建临时表,CTE 又不支持动态深度。
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
- 最稳的方式:把数组长度取出来(
JSON_LENGTH(json_array)),用WHILE循环配合JSON_EXTRACT(json_array, CONCAT('$[', i, ']'))拼路径 - i 从 0 开始,上限是
JSON_LENGTH(...) - 1,别写成导致越界取 NULL - 每次提取后建议用
JSON_TYPE()判断类型,避免把对象当字符串处理
性能和兼容性陷阱:JSON 字段不能建传统索引
给 JSON 字段加 INDEX 不起作用,WHERE JSON_EXTRACT(data, '$.id') = 123 一定会全表扫描。想加速查询,必须建生成列(generated column)再索引。
- 建表时定义:
id_val INT AS (JSON_EXTRACT(data, '$.id')) STORED,然后CREATE INDEX idx_id ON tbl(id_val) - 已存在表需先
ADD COLUMN,再ALTER TABLE ... PERSISTENT(5.7.13+ 才支持 STORED) - 注意:生成列表达式必须确定、无副作用,
JSON_UNQUOTE()必须显式写出,否则索引值带引号,导致= 123匹配失败
实际写存储过程时,JSON 处理最耗神的不是语法,而是“什么时候该转成关系型字段”。比如用户标签数组存成 JSON 看似灵活,但一旦要按标签分组统计,就不得不在过程里反复解析——这时候不如拆成关联表。别为了“看起来统一”牺牲可维护性。

















