MySQL JSON_TABLE 的 FOR ORDINALITY 怎么保留数组原始序号
要保留 MySQL JSON 数组元素的位置,最直接的写法是在 JSON_TABLE() 的 COLUMNS 中声明一个 FOR ORDINALITY 列,并让行路径使用 '$[*]'。它会为展开后的每一行生成从 1 开始的序号;如果应用需要零基索引,再在查询结果中减 1。
关键边界是:序号统计的是当前 COLUMNS 的行源,不是 JSON 文本里永远固定的下标。想保留原始数组位置时,先完整展开,再用 SQL 条件过滤,不要先把路径改成只匹配部分元素。
FOR ORDINALITY的序号从 1 开始,列类型是无符号整数。- 嵌套
NESTED PATH有自己的计数作用域,父级序号和子级序号应分别命名。 - 使用
$[*]全量展开后再WHERE过滤,才能让保留下来的记录继续携带原数组位置。
一、用 $[*] 展开数组并声明 FOR ORDINALITY
假设接口把商品明细放在 JSON 数组中,需要把数组位置一起落到查询结果。row_no FOR ORDINALITY 不需要再写数据类型或 PATH,它负责对当前行源逐行编号。
-- $[*] 让数组每个元素成为一行,row_no 从 1 开始
SET @payload = '[{"sku":"A-10","qty":2},{"sku":"B-20","qty":5},{"sku":"C-30","qty":1}]';
SELECT jt.row_no, jt.sku, jt.qty
FROM JSON_TABLE(
@payload,
'$[*]' COLUMNS (
row_no FOR ORDINALITY,
sku VARCHAR(32) PATH '$.sku',
qty INT PATH '$.qty'
)
) AS jt;
结果中的 row_no 依次是 1、2、3。它表示当前数组行源中的位置,不是业务主键,也不会因为 sku 相同就合并行。需要和应用数组下标对齐时,可以输出 CAST(row_no AS SIGNED) - 1,避免直接对无符号值做减法时产生边界误解。
![MySQL JSON_TABLE 使用 $[*] 展开 JSON 数组并由 FOR ORDINALITY 生成行位置的静态关系图](/uploads/20260909/1788905099-038ee88658-c6e16129ef-mysql-json-table-ordinality-scope.webp)
| 写法 | 含义 | 适用判断 |
|---|---|---|
row_no FOR ORDINALITY | 当前行源的一基序号 | 保留展开位置 |
CAST(row_no AS SIGNED) - 1 | 转换为零基位置 | 对接数组下标 |
sku PATH '$.sku' | 读取元素字段 | 保留业务数据 |
二、在嵌套 COLUMNS 中分别记录父子序号
JSON 经常是“订单数组下还有明细数组”。这时不要只保留一个序号:顶层 order_no 标识第几个订单,嵌套层的 item_no 标识该订单里的第几个明细。两个 FOR ORDINALITY 位于不同的 COLUMNS 作用域,组合起来才能定位一条明细。
-- 父级和子级各自编号,组合键可定位具体明细
SET @orders = '[
{"order_id":101,"items":[{"name":"键盘","qty":1},{"name":"鼠标","qty":2}]},
{"order_id":102,"items":[{"name":"耳机","qty":1}]}
]';
SELECT order_no, order_id, item_no, item_name, qty
FROM JSON_TABLE(
@orders,
'$[*]' COLUMNS (
order_no FOR ORDINALITY,
order_id INT PATH '$.order_id',
NESTED PATH '$.items[*]' COLUMNS (
item_no FOR ORDINALITY,
item_name VARCHAR(64) PATH '$.name',
qty INT PATH '$.qty'
)
)
) AS jt;
第一笔订单的明细序号是 1、2,第二笔订单重新从 1 开始。不要把 item_no 当成整个文档的全局序号;如果业务需要全局位置,应另外定义跨层组合规则或保存原始 JSON 路径。

三、根据业务需要转换零基索引并安全取值
数据库结果通常更适合展示一基序号,因为读者看到的“第 1 项”就是 1;JavaScript、Go 切片等应用容器常用零基下标。建议同时保留原始的 row_no,只在输出层派生 array_index,这样排查数据时不会丢掉 MySQL 的原始计数语义。
-- 保留一基序号,同时派生应用侧常用的零基下标
SELECT
jt.row_no,
CAST(jt.row_no AS SIGNED) - 1 AS array_index,
jt.sku,
jt.qty
FROM JSON_TABLE(
@payload,
'$[*]' COLUMNS (
row_no FOR ORDINALITY,
sku VARCHAR(32) PATH '$.sku',
qty INT PATH '$.qty' DEFAULT '0' ON EMPTY
)
) AS jt;
字段缺失时,DEFAULT '0' ON EMPTY 只处理路径没有值的情况;它和序号没有关系。序号列本身由行源产生,不要为它额外写 PATH。对象或数组被写入标量列时,还要按需要选择 ON ERROR 策略。
四、过滤时避免把新序号误当成原始位置
如果只想留下数量大于 1 的元素,应该先用 '$[*]' 展开,再在外层 WHERE 过滤。这样第二个数组元素即使被过滤掉,第三个元素仍会保留它原来的 row_no = 3。
-- 先生成原始位置,再过滤;row_no 不会因删行而重排
SELECT row_no, sku, qty
FROM JSON_TABLE(
@payload,
'$[*]' COLUMNS (
row_no FOR ORDINALITY,
sku VARCHAR(32) PATH '$.sku',
qty INT PATH '$.qty'
)
) AS jt
WHERE qty > 1
ORDER BY row_no;
相反,如果把行路径改成只匹配某一部分数组元素,FOR ORDINALITY 看到的就是这个新行源,序号可能从 1 重新计数。因此要先确定需求:是“筛选后的结果序号”,还是“原始 JSON 数组下标”。前者可以直接使用筛选后的行源,后者应全量展开后过滤,并保留序号列。
相关问题
FOR ORDINALITY 的序号从 0 还是从 1 开始?
从 1 开始。对接零基数组时,保留原列并在外层用有符号表达式减 1。
嵌套数组的 item_no 为什么每个父对象都从 1 开始?
因为它属于嵌套 COLUMNS 的独立计数作用域。要定位明细,应同时记录父级序号或父级业务 ID。
过滤后想保留原来的数组位置怎么办?
用 $[*] 完整展开,在关系结果上使用 WHERE 过滤,并保留 FOR ORDINALITY 列;不要把筛选后的新行源序号当成原始下标。
Go bufio.Scanner 自定义 SplitFunc 怎么识别带前缀的日志记录
- 上一篇
- Go bufio.Scanner 自定义 SplitFunc 怎么识别带前缀的日志记录
- 下一篇
- Go errors.Join 返回的错误怎么逐个用 errors.Is 判断
-
- 数据库 · MySQL | 2小时前 |
- MySQL 复制延迟升高时怎么区分 SQL 线程和 IO 线程
- 304浏览 收藏
-
- 数据库 · MySQL | 5小时前 | MySQL事件 · 事件调度器 · 任务表排查 · mysql 定时任务 CREATE EVENT Event Scheduler INFORMATION_SCHEMA.EVENTS
- MySQL 事件调度器执行了但任务表没有更新怎么排查
- 486浏览 收藏
-
- 数据库 · MySQL | 10小时前 |
- MySQL 事务隔离级别改成 READ COMMITTED 后会少什么锁
- 284浏览 收藏
-
- 数据库 · MySQL | 13小时前 | MySQL · 递归查询 · CTE · mysql WITH RECURSIVE CTE
- MySQL CTE 递归查询为什么会超过默认深度
- 270浏览 收藏
-
- 数据库 · MySQL | 14小时前 | MySQL · 窗口函数 · SQL排序 · mysql 稳定排序 窗口函数 ROW_NUMBER
- MySQL 窗口函数排序相同值时怎么保证结果稳定
- 418浏览 收藏
-
- 数据库 · MySQL | 16小时前 |
- MySQL 生成列索引为什么比直接查 JSON 更稳定
- 401浏览 收藏
-
- 前端进阶之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测试功能,助您快速选择最适合项目的高性能大语言模型。
- 37次使用
-
- SuperCLUE
- SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
- 189次使用
-
- C-Eval
- 深入了解C-Eval中文评估套件,涵盖52个学科与4级难度。本文详解其功能特点、Zero-shot/Few-shot使用方法及代码示例,助您全面评测LLM中文理解与泛化能力。
- 129次使用
-
- AI Prompt Library
- 探索AI Prompt Library免费资源库,涵盖营销、写作及多场景AI提示词。兼容ChatGPT、Claude等工具,一键复制优化输出,提升工作效率。
- 53次使用
-
- Generrated
- Generrated汇集9300+张DALL·E生成图像及对应提示词,支持查看完整图集、对比DALL·E 2与3版本差异,是AI绘图新手学习Prompt设计与获取创作灵感的实用工具。
- 40次使用
-
- MySQL 明明加了索引,为什么查询还是很慢?先查这 6 个点
- 2026-06-27 374浏览
-
- golang MySQL实现对数据库表存储获取操作示例
- 2022-12-22 499浏览
-
- golang 基于 mysql 简单实现分布式读写锁
- 2023-01-07 384浏览
-
- 详解如何利用GORM实现MySQL事务
- 2023-01-07 184浏览
-
- Go语言实现操作MySQL的基础知识总结
- 2023-01-23 265浏览

