当前位置:首页 > 文章列表 > 数据库 > MySQL > MySQL JSON_TABLE 展开数组时如何保留缺失字段

MySQL JSON_TABLE 展开数组时如何保留缺失字段

来源:17golang原创 2026-09-10 17:52:44 0浏览 收藏

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 得到 SQL NULL;必填字段可以改用 ERROR ON EMPTY
  • EXISTS PATH 返回存在性标记,可把缺失、显式 JSON null 和空字符串分开处理。

先把数组元素和字段取值分成两层

JSON_TABLE() 的第一个路径是行源。对一个对象数组使用 '$[*]',结果的基本单位就是数组元素。COLUMNS 中的路径只负责给这一行投影列,所以对象里少了 city,影响的是 city 这一列,不是已经由行源建立的整行。

下面的例子故意让第二个对象没有 cityidname 是必填字段,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_present0。这正是“保留数组元素、允许可选列为空”的效果。

MySQL JSON_TABLE 从 JSON 数组行源到 NULL ON EMPTY 保留关系行的静态结构图
图1:查看数组元素、JSON_TABLE 列定义和关系行的边界,理解字段缺失时为什么只让列为空而不丢掉整行。

用 NULL ON EMPTY 保留数组元素对应的行

对可选标量列,明确写 NULL ON EMPTY 比依赖默认行为更容易读懂,也方便以后审查导入规则。它处理的是 JSON 路径没有匹配值的情况;它不会把空字符串改成 NULL,也不会把一个存在但类型不对的对象自动变成业务上可接受的值。

输入状态city 列city_present业务含义
没有 city 键NULL0未提供
city 为 JSON nullNULL1明确提供了空值
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 与字段缺失一起覆盖成同一个显示文本。先保留原始状态,再在展示层或业务层决定是否补默认值,通常更稳妥。

MySQL JSON_TABLE 用 city 值列与 EXISTS PATH 区分缺失 JSON null 和空字符串的静态关系图
图2:将 city 值列与 city_present 存在性列并列查看,区分没有键、键值为 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 和存在性标记,再由业务层决定默认值。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go encoding/csv Comment 读取带注释行的文件怎么配置 CommentGo encoding/csv Comment 读取带注释行的文件怎么配置 Comment
上一篇
Go encoding/csv Comment 读取带注释行的文件怎么配置 Comment
LiblibAI能画文章头图吗?从横图留白到系列风格的适用范围
下一篇
LiblibAI能画文章头图吗?从横图留白到系列风格的适用范围
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    66次使用
  • SuperCLUE中文大模型评测基准:功能、能力维度与应用指南
    SuperCLUE
    SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
    224次使用
  • C-Eval中文评测基准:大语言模型多学科能力评估指南
    C-Eval
    深入了解C-Eval中文评估套件,涵盖52个学科与4级难度。本文详解其功能特点、Zero-shot/Few-shot使用方法及代码示例,助您全面评测LLM中文理解与泛化能力。
    148次使用
  • AI Prompt Library:免费AI提示词库,助力ChatGPT高效创作与营销
    AI Prompt Library
    探索AI Prompt Library免费资源库,涵盖营销、写作及多场景AI提示词。兼容ChatGPT、Claude等工具,一键复制优化输出,提升工作效率。
    81次使用
  • Generrated:DALL·E 2/3 AI绘画提示词灵感库与图像对比平台
    Generrated
    Generrated汇集9300+张DALL·E生成图像及对应提示词,支持查看完整图集、对比DALL·E 2与3版本差异,是AI绘图新手学习Prompt设计与获取创作灵感的实用工具。
    60次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码