mysql 5.7 完全不存在 json_table() 函数,该函数首次出现于 mysql 8.0.4;5.7 仅支持 json_extract() 等基础 json 函数,无法原生展开 json 数组为多行结果。

MySQL 5.7 根本没有 JSON_TABLE() 函数
不是“不支持”或“需要开启配置”,而是该函数在 MySQL 5.7 中**完全不存在**——它首次出现在 MySQL 8.0.4 版本。你执行 SELECT JSON_TABLE('[]', '$' COLUMNS (x INT PATH '$')); 会直接报错 ERROR 1305 (42000): FUNCTION json_table does not exist,连语法解析都过不去。
5.7 的 JSON 函数集止步于 JSON_EXTRACT()、JSON_CONTAINS()、-> 和 ->> 等基础能力,所有涉及“将 JSON 数组展开为多行结果”的需求(即 Oracle JSON_TABLE 的核心语义),5.7 均无原生支持。
5.7 中模拟 JSON_TABLE 的常见错误写法
很多人试图用 JSON_EXTRACT() + 子查询或变量拼接来“动态展开”,但这类写法几乎必然失败:
-
JSON_LENGTH()返回数组长度没错,但无法用它驱动运行时循环——MySQL 5.7 不支持在普通 SELECT 中使用变量控制迭代次数 - 用
UNION ALL手动枚举索引(如[0],[1],[2])看似可行,但必须提前知道最大长度;一旦实际数据超出预设范围,新元素就永远查不到 - 把 JSON 字段当字符串用
SUBSTRING_INDEX()或正则硬切——遇到嵌套对象、转义引号、换行符时立刻解析错乱,JSON_VALID()检查全挂 - 依赖存储过程生成临时表再 JOIN:5.7 存储过程无法返回结果集给外部查询,调用后仍需额外 SELECT,且并发下容易锁表
真正可用的 5.7 替代方案(仅限已知固定长度场景)
如果业务确认 JSON 数组长度 ≤ N(比如最多 5 个地址),可建一个静态序号表,再用 JOIN + JSON_EXTRACT() 安全展开:
CREATE TABLE seq_0_to_4 (i INT PRIMARY KEY); INSERT INTO seq_0_to_4 VALUES (0),(1),(2),(3),(4);
然后查询:
SELECT
t.id,
JSON_UNQUOTE(JSON_EXTRACT(t.addr_info, CONCAT('$[', s.i, '].AddressCode'))) AS address_code,
JSON_UNQUOTE(JSON_EXTRACT(t.addr_info, CONCAT('$[', s.i, '].AddressDetail'))) AS address_detail
FROM person_info t
JOIN seq_0_to_4 s
ON s.i
<p>注意要点:</p>
- 必须用
JSON_LENGTH()控制 JOIN 范围,否则会产生笛卡尔积空行 - 每列提取都要显式
JSON_UNQUOTE(),否则字符串带双引号 -
CONCAT()构造路径时不能有空格,'$[' || s.i || ']'在 5.7 不生效(不支持||拼接) - 若数组含
null元素,JSON_EXTRACT()返回NULL,需靠WHERE ... IS NOT NULL过滤掉
升级到 8.0 后 JSON_TABLE() 的关键差异
8.0 的 JSON_TABLE() 是真正的关系型转换器,不是字符串模拟:
- 路径表达式支持
$[*]、$[0 to 2]等语法,无需预估长度 - 可定义
ON ERROR NULL/ON EMPTY DEFAULT处理缺失字段,5.7 里只能靠层层IFNULL() - 支持嵌套
NESTED PATH展开多层结构(如地址里的电话列表),5.7 只能靠多层 JOIN 模拟,SQL 膨胀到难以维护 - 执行计划中显示为
materialized操作,优化器能评估成本;5.7 的 UNION ALL 方案在 EXPLAIN 里全是ALL扫描
最易被忽略的是:8.0 的 JSON_TABLE() 对输入 JSON 的格式校验更严格——若源字段含非法 Unicode 或未转义控制字符,5.7 可能静默返回空值,而 8.0 直接报错中断查询。











