JSON_TABLE 是 MySQL 8.0.4+ 用于将 JSON 数组展开为关系型行集的原生函数,必须在 FROM 子句中使用,适用于权限、商品 ID 等数组字段展开场景。

JSON_TABLE 是什么,什么时候必须用它
JSON_TABLE 是 MySQL 8.0.4+ 引入的函数,用于把 JSON 数组“炸开”成关系型行集。它不是语法糖,而是唯一能原生将嵌套 JSON 数组转为多行结果的方式——JSON_EXTRACT 或 -> 操作符只能取值,不能展开;想用 JOIN 或子查询硬凑,会漏数据或爆炸式笛卡尔积。
常见场景包括:
- 表中某字段存了用户权限列表:
{"roles": ["admin", "editor"]},要查所有带admin的用户 - 订单记录里存了商品 ID 数组:
{"items": [101, 102, 105]},需关联商品表查明细 - 日志字段含操作步骤数组,要统计每步耗时分布
基本写法:FROM 子句里直接调用 JSON_TABLE
JSON_TABLE 必须出现在 FROM 子句中(不能放 SELECT 里),结构固定为:
JSON_TABLE( json_doc, path COLUMNS (column_def, ...) ) AS alias
关键点:
-
json_doc是源 JSON,可以是列名(如data)、表达式(如data->'$.items')或字面量(如'[1,2,3]') -
path是数组路径,必须以$[<em>]</em>结尾,例如'$.roles[]'、'$[*]' -
COLUMNS定义输出列:支持name FOR ORDINALITY(序号)、name VARCHAR(20) PATH '$'(取当前数组元素值)、name INT PATH '$.id'(取对象子字段)
示例:从 users 表展开 roles 数组
SELECT u.id, jt.role FROM users u, JSON_TABLE(u.profile, '$.roles[*]' COLUMNS (role VARCHAR(20) PATH '$')) AS jt;
常见错误和坑点
- 报错
ERROR 3143 (42000): Invalid path expression:路径没写 [<em>]</em>,比如用了 '$.roles' 而非 '$.roles[]'
- 展开后行数为 0:源 JSON 字段为
NULL、空字符串、或根本不是合法 JSON(可用 JSON_VALID(data) 先过滤)
- 字段类型不匹配导致截断:比如用
VARCHAR(5) 接长度为 8 的字符串,静默截断不报错
- 对象数组里取深层字段写错路径:若数组元素是
{"user": {"name": "Alice"}},正确写法是 name VARCHAR(50) PATH '$.user.name',不是 '$.name'
- 性能隐患:对大表 + 大 JSON 字段频繁展开,建议在应用层预处理,或加生成列 + 索引(如
ALTER TABLE users ADD role_list TEXT AS (profile->>'$.roles'))
和 JSON_CONTAINS 配合做条件过滤
ERROR 3143 (42000): Invalid path expression:路径没写 [<em>]</em>,比如用了 '$.roles' 而非 '$.roles[]'
NULL、空字符串、或根本不是合法 JSON(可用 JSON_VALID(data) 先过滤)VARCHAR(5) 接长度为 8 的字符串,静默截断不报错{"user": {"name": "Alice"}},正确写法是 name VARCHAR(50) PATH '$.user.name',不是 '$.name'
ALTER TABLE users ADD role_list TEXT AS (profile->>'$.roles'))单纯展开不够,常需边展开边过滤。别在 WHERE 里对原始 JSON 字段用 JSON_CONTAINS(无法利用展开逻辑),而应先展开再筛:
SELECT u.id, jt.role FROM users u, JSON_TABLE(u.profile, '$.roles[*]' COLUMNS (role VARCHAR(20) PATH '$')) AS jt WHERE jt.role = 'admin';
如果要查“同时有 admin 和 editor”的用户,得用聚合(如 HAVING COUNT(DISTINCT jt.role) = 2)或两次 EXISTS 子查询——JSON_TABLE 本身不支持跨行逻辑判断。
JSON_TABLE 的路径解析和列映射是静态的,运行时不推导结构。一旦 JSON 格式变化(比如数组变对象、字段名改大小写),查询会静默返回空或错列,上线前务必用真实数据验证。


















