JSON_TABLE必须配合LATERAL使用才能正确展开JSON数组,路径须为数组路径(如'$[*]'),COLUMNS中PATH相对于数组元素,避免重复解析和类型误转。

JSON_TABLE 用法核心:必须配合 LATERAL 才能展开数组
直接在 FROM 子句里写 JSON_TABLE() 不会报错,但结果常为空或只取首项——因为 MySQL 要求对 JSON 数组展开时,必须用 LATERAL 关键字声明依赖关系。否则优化器可能跳过行级展开逻辑。
典型错误写法:SELECT * FROM t, JSON_TABLE(t.data, '$[*]' COLUMNS (id INT PATH '$.id')) AS jt —— 这种写法在 MySQL 8.0.22+ 会静默失败(返回空结果),不是语法错,是语义错。
正确姿势:
- 必须用
LATERAL显式关联源表与 JSON_TABLE -
JSON_TABLE的路径表达式必须是数组路径(如'$[*]'或'$.items[*]'),不能是对象路径(如'$') - 源字段必须是合法 JSON(可用
JSON_VALID()预检)
处理嵌套结构:路径和 COLUMNS 定义要严格匹配层级
如果 JSON 是 {"user": {"name": "Alice", "tags": ["admin", "dev"]}},想展开 tags 数组,不能直接写 '$.tags[*]' —— 因为 JSON_TABLE 的路径是从根开始解析的,而你传入的是整行字段值,所以路径要写全:'$.user.tags[*]'。
COLUMNS 里的 PATH 是相对于该数组元素的路径,不是整个 JSON。例如展开 tags 后取每个字符串值,就用 tag VARCHAR(20) PATH '$',而不是 '$.user.tags'。
常见坑:
- 误写
PATH '$.tag'(数组元素本身是字符串,没有tag字段)→ 返回 NULL - 没加
FOR ORDINALITY却想按原序处理 → MySQL 不保证顺序,尤其数据量大时 - 用
INT PATH '$.id'解析字符串型数字(如"123")→ 正常转,但"abc"会变 0,不报错
性能关键:避免在 WHERE 或 JOIN 条件里重复解析 JSON
JSON_TABLE 是行集生成函数,每次调用都会重新解析 JSON 字符串。如果在 WHERE 中写 JSON_CONTAINS(data, '"admin"', '$.roles') 又在 FROM 里用 JSON_TABLE(data, '$.roles[*]'),等于同一字段被解析两次。
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
更高效的做法是:先用 JSON_TABLE 展开,再在外部过滤。例如:
SELECT u.id, jt.role FROM users u LATERAL JSON_TABLE(u.data, '$.roles[*]' COLUMNS (role VARCHAR(20) PATH '$')) AS jt WHERE jt.role = 'admin';
而不是:
SELECT * FROM users u WHERE JSON_CONTAINS(u.data, '"admin"', '$.roles') AND ... -- 再展开,重复解析
另外注意:JSON_TABLE 无法利用索引,所有过滤都发生在展开后,大数据量下务必预过滤源表(比如先 WHERE status = 'active')。
兼容性与调试:MySQL 版本和 JSON 格式容错边界
JSON_TABLE 从 MySQL 8.0.4 引入,但早期版本(8.0.4–8.0.19)对空数组、null 元素、非标准 JSON(如尾部逗号)容忍度低,容易报 Invalid JSON text 或静默跳过行。
调试建议:
- 先用
SELECT id, JSON_VALID(data), JSON_LENGTH(data, '$.items') FROM t LIMIT 5确认字段可解析且有数据 - 测试时加
FOR ORDINALITY列,观察是否漏行:COLUMNS (idx FOR ORDINALITY, val VARCHAR(50) PATH '$') - 遇到
Empty set但预期有结果,优先检查:JSON_EXTRACT(data, '$.items')是否返回NULL(说明路径错)或[](说明数组为空)
真正麻烦的是混合类型数组(如 [1, "foo", null, {"x":2}]),JSON_TABLE 会按字段定义类型强制转换,INT PATH '$' 遇到字符串会得 0,且不提示——这种场景建议先用 JSON_TYPE() 分离再处理。

















