JSON_TABLE是MySQL 8.0+中唯一能将JSON数组展开为多行关系结果集的函数,必须用于需对JSON数组元素逐项JOIN、WHERE筛选或聚合的场景。
JSON_TABLE 是什么,什么时候必须用它
不是“可选替代方案”,而是 MySQL 中
唯一能把 JSON 数组展开成标准行集(即多行结果)的函数
。如果你的 JSON 字段存的是数组(比如
),而你想对每个元素做
、加
条件筛选、或与其他表关联,
或
操作符只能返回单个值或 NULL,没法生成多行 —— 这时候就必须上
。
常见错误现象:
用
只能取第一个对象,想遍历全部?手动写 N 个
,
… 不现实
用
却没加
或写错别名,报错
使用场景明确包括:
日志字段里存了多个标签
,要统计各标签出现次数
用户权限字段是对象数组
,需查出所有含
的用户
订单明细以 JSON 数组存在主表字段中,不想拆表也要支持按商品 ID 聚合
怎么写一个可用的 JSON_TABLE 查询
核心结构固定:
,漏任何一部分都语法报错。
关键参数差异和实操建议:
php版微信js-sdk支付接口类
php版微信js-sdk支付接口类
下载
必须是合法 JSON 字符串或列名,如果是字段,建议先用
或
过滤,避免解析失败导致整行丢弃
写
表示遍历整个数组;若只想处理前 3 个元素,得先用
截取再传入
里每个
格式为
,注意:
必须显式声明(如
,
),不能写
(MySQL 不支持)
是相对于当前数组元素的路径,不是整个 JSON 的根路径
加
会多出一列序号(从 1 开始),方便排序或去重
示例(提取用户权限数组中的所有 role):
容易踩的坑:NULL、空数组、嵌套结构怎么处理
对非法输入非常严格,稍不注意就静默丢数据:
如果
是
或非数组(比如传了个对象
),整行不会出现在结果中,也不会报错 —— 建议在外层用
预过滤
空数组
会导致
不生成任何行,这符合预期,但容易被误判为“没数据”而非“数组为空”
嵌套太深(如
)不能直接两层
套用,必须分步:先用外层
展开
,再对每行的
字段单独调一次
性能提示:
无法走索引,纯内存解析,字段越大越慢;如果高频查询某 key,优先建虚拟列 + 索引(如
)
不要用
处理超长数组(>100 元素),考虑应用层拆分或预计算
复杂点在于:它不提供“跳过解析失败项”的开关,一旦某个数组元素的
找不到字段(比如
不存在),该行直接被忽略,连
都不给 —— 这和
的宽容行为完全不同。
JSON_TABLE[{"id":1,"name":"a"},{"id":2,"name":"b"}]JOINWHEREJSON_EXTRACT->JSON_TABLEJSON_EXTRACT(json_col, '$[0]')$[0]$[1]SELECT ... FROM t, JSON_TABLE(...)LATERALUnknown column 't.json_col' in 'field list'["bug", "ui", "backend"][{"role":"admin"},{"role":"editor"}]"admin"JSON_TABLE(json_expr, path COLUMNS (col_def, ...)) AS aliasjson_exprISJSON()JSON_VALID()path$[*]JSON_EXTRACT(json_col, '$[0 to 2]')COLUMNScol_defcol_name type PATH '$.key' [ORDINALITY | EXISTS]typeVARCHAR(50)INTTEXTPATHORDINALITYSELECT u.id, jt.role
FROM users u,
JSON_TABLE(u.permissions, '$[*]'
COLUMNS (role VARCHAR(20) PATH '$.role')
) AS jt
WHERE jt.role = 'admin';JSON_TABLEjson_exprNULL{}WHERE JSON_TYPE(permissions) = 'ARRAY'[]JSON_TABLE$.items[].details[].price$[*]JSON_TABLEitemsdetailsJSON_TABLEJSON_TABLEALTER TABLE users ADD COLUMN first_role VARCHAR(20) GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(permissions, '$[0].role'))) STOREDJSON_TABLEPATH$.roleNULLJSON_EXTRACT