MySQL JSON_TABLE 展开数组时如何保留缺失字段
MySQL 用 JSON_TABLE() 展开数组时,数组元素缺少某个可选字段,不应该让整条元素消失。做法是让行源使用 '$[*]',再给可选列写上 NULL ON EMPTY;如果还要区分“没有这个键”和“键存在但值是 JSON null”,再增加一列 EXISTS PATH。
保留缺失字段的关键不是给 JSON 补键,而是把“数组元素生成行”和“列路径取值”分开处理:行源决定保留哪一行,NULL ON EMPTY决定缺失列填什么,EXISTS PATH决定字段是否真的出现过。
官方文档:https://dev.mysql.com/doc/refman/8.4/en/json-table-functions.html
'$[*]'会为数组中的每个对象建立一行,单个字段缺失不会自动删除该行。- 可选字段用
NULL ON EMPTY得到 SQLNULL;必填字段可以改用ERROR ON EMPTY。 EXISTS PATH返回存在性标记,可把缺失、显式 JSON null 和空字符串分开处理。
先把数组元素和字段取值分成两层
JSON_TABLE() 的第一个路径是行源。对一个对象数组使用 '$[*]',结果的基本单位就是数组元素。COLUMNS 中的路径只负责给这一行投影列,所以对象里少了 city,影响的是 city 这一列,不是已经由行源建立的整行。
下面的例子故意让第二个对象没有 city。id 和 name 是必填字段,city 是可选字段:
WITH source AS (
SELECT JSON_ARRAY(
JSON_OBJECT('id', 101, 'name', '上海仓', 'city', '上海'),
JSON_OBJECT('id', 102, 'name', '杭州仓')
) AS doc
)
SELECT jt.id, jt.name, jt.city, jt.city_present
FROM source
CROSS JOIN JSON_TABLE(
source.doc,
'$[*]' COLUMNS (
id INT PATH '$.id' ERROR ON EMPTY, -- 主键缺失时拒绝静默导入。
name VARCHAR(40) PATH '$.name' ERROR ON EMPTY, -- 名称是必填列。
city VARCHAR(40) PATH '$.city' NULL ON EMPTY, -- 缺失城市只填 SQL NULL。
city_present TINYINT EXISTS PATH '$.city' -- 单独记录 city 键是否存在。
)
) AS jt;
结果中仍然有两行:第一行的 city 是“上海”,第二行的 city 是 SQL NULL,但第二行的 city_present 是 0。这正是“保留数组元素、允许可选列为空”的效果。

用 NULL ON EMPTY 保留数组元素对应的行
对可选标量列,明确写 NULL ON EMPTY 比依赖默认行为更容易读懂,也方便以后审查导入规则。它处理的是 JSON 路径没有匹配值的情况;它不会把空字符串改成 NULL,也不会把一个存在但类型不对的对象自动变成业务上可接受的值。
| 输入状态 | city 列 | city_present | 业务含义 |
|---|---|---|---|
| 没有 city 键 | NULL | 0 | 未提供 |
| city 为 JSON null | NULL | 1 | 明确提供了空值 |
city 为 "" | 空字符串 | 1 | 提供了空文本 |
如果下游只关心显示值,单独的 city 列已经够用;如果要做补值、审计或数据质量统计,建议保留 city_present。否则“接口没传城市”和“接口传了 null”会在落库后变成同一种状态。
用 EXISTS PATH 区分缺失、JSON null 和空字符串
EXISTS PATH 列不负责返回城市文本,而是判断路径上是否有数据。把它和普通的 PATH 列并列声明,就能让查询结果携带状态信息。MySQL 文档对 JSON_TABLE() 的列类型也把两者分开:普通路径列负责取值,EXISTS PATH 负责返回 1 或 0。
SELECT jt.order_id,
jt.city,
jt.city_present,
CASE
WHEN jt.city_present = 0 THEN '缺少 city 键' -- 先判断键是否出现。
WHEN jt.city IS NULL THEN 'city 明确为 JSON null' -- 键在,但值为空。
WHEN jt.city = '' THEN 'city 是空字符串' -- 空文本不等于缺失。
ELSE 'city 有实际文本'
END AS city_state
FROM JSON_TABLE(
'[
{"order_id": 1, "city": "上海"},
{"order_id": 2, "city": null},
{"order_id": 3},
{"order_id": 4, "city": ""}
]',
'$[*]' COLUMNS (
order_id INT PATH '$.order_id' ERROR ON EMPTY, -- 订单号缺失时让导入失败。
city VARCHAR(40) PATH '$.city' NULL ON EMPTY, -- 缺失和 JSON null 的值都可落为 NULL。
city_present TINYINT EXISTS PATH '$.city' -- 用 0/1 补足存在性信息。
)
) AS jt;
这里不要用 COALESCE(city, '未提供') 来代替存在性列,因为它会把 JSON null 与字段缺失一起覆盖成同一个显示文本。先保留原始状态,再在展示层或业务层决定是否补默认值,通常更稳妥。

必填字段、类型错误和嵌套数组要单独定规则
缺失字段只是一个输入状态,不能和类型转换错误混为一谈。订单号、业务编码这类必填列可以使用 ERROR ON EMPTY;可选金额则可以把缺失和类型错误分开写清楚:
COLUMNS (
order_id INT PATH '$.order_id' ERROR ON EMPTY ERROR ON ERROR, -- 必填且必须是整数。
amount DECIMAL(12, 2) PATH '$.amount'
NULL ON EMPTY ERROR ON ERROR -- 缺失可为空,传入对象或非法数字则报错。
)
如果缺失的是嵌套数组,使用 NESTED PATH '$.items[*]' 时要观察父行和子列的关系。没有子项时,嵌套列可能以补空行的形式出现;若业务只要真正存在的子项,再用子项主键做过滤。不要为了消除空值而直接把整个父对象过滤掉,否则会丢失“父对象存在但暂时没有子项”的信息。
常见问题
NULL ON EMPTY 会不会删除缺少字段的数组元素?
不会。数组元素是否生成行由行源路径决定,NULL ON EMPTY 只决定当前列在路径无匹配时的值。
字段缺失和 JSON null 为什么都显示为 NULL?
普通 PATH 列的值投影确实可能相同,所以需要并列增加 EXISTS PATH 列,用 0/1 表示键是否出现。
可以用 DEFAULT ON EMPTY 直接补默认城市吗?
可以,但默认值属于 JSON 字符串并要符合目标列类型。若还需要审计原始输入,建议先保留 NULL 和存在性标记,再由业务层决定默认值。
Go encoding/csv Comment 读取带注释行的文件怎么配置 Comment
- 上一篇
- Go encoding/csv Comment 读取带注释行的文件怎么配置 Comment
- 下一篇
- LiblibAI能画文章头图吗?从横图留白到系列风格的适用范围
-
- 数据库 · MySQL | 1小时前 |
- MySQL CTE 多次引用时为什么可能重复物化
- 237浏览 收藏
-
- 数据库 · MySQL | 3小时前 | MySQL · 执行计划 · 索引优化 · mysql explain OR条件 Index Merge
- MySQL OR 条件什么时候会选择 Index Merge
- 373浏览 收藏
-
- 数据库 · MySQL | 6小时前 |
- MySQL 事务隔离级别下普通 SELECT 为什么看不到新提交
- 385浏览 收藏
-
- 数据库 · MySQL | 7小时前 | MySQL · 索引 · 性能优化 · 执行计划 · mysql explain optimizer hint FORCE INDEX USE INDEX
- MySQL optimizer hint 和 FORCE INDEX 怎么选择
- 478浏览 收藏
-
- 数据库 · MySQL | 8小时前 | MySQL · explain · 性能分析 · JSON执行计划 · 嵌套循环 · mysql 执行计划 EXPLAIN FORMAT=JSON nested_loop 查询成本
- MySQL EXPLAIN FORMAT=JSON 怎么查看嵌套循环成本
- 166浏览 收藏
-
- 数据库 · MySQL | 14小时前 |
- MySQL collation 不一致导致 JOIN 报错怎么统一
- 446浏览 收藏
-
- 数据库 · MySQL | 22小时前 |
- MySQL 递归 CTE 生成日期序列时为什么列类型会截断
- 104浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- MySQL 递归 CTE 遍历树数据时怎么防止无限循环
- 142浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- MySQL invisible index 如何安全观察索引下线影响
- 300浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 66次使用
-
- SuperCLUE
- SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
- 224次使用
-
- C-Eval
- 深入了解C-Eval中文评估套件,涵盖52个学科与4级难度。本文详解其功能特点、Zero-shot/Few-shot使用方法及代码示例,助您全面评测LLM中文理解与泛化能力。
- 148次使用
-
- AI Prompt Library
- 探索AI Prompt Library免费资源库,涵盖营销、写作及多场景AI提示词。兼容ChatGPT、Claude等工具,一键复制优化输出,提升工作效率。
- 81次使用
-
- Generrated
- Generrated汇集9300+张DALL·E生成图像及对应提示词,支持查看完整图集、对比DALL·E 2与3版本差异,是AI绘图新手学习Prompt设计与获取创作灵感的实用工具。
- 60次使用
-
- MySQL 分区表怎么处理跨分区唯一键:分区列约束与建表取舍
- 2026-08-30 501浏览
-
- MySQL权限管理设置全攻略
- 2026-03-29 501浏览
-
- MySQL分片实现方法及常见方案解析
- 2025-06-24 501浏览
-
- MySQL表空间碎片怎么清理?超详细优化教程
- 2025-06-13 501浏览
-
- MySQL排序性能优化技巧及方法
- 2025-06-04 501浏览

