PG JSON 遍历终极指南:7 个函数 + 5 个实战场景,看完直接抄搞不定 jsonb 循环遍历?从 jsonb_array_elements 到 LATERAL JOIN,一篇讲透
适用版本PostgreSQL 9.4本文所有函数基于jsonb类型json类型函数名为json_array_elements/json_each等去掉b即可阅读时间约 12 分钟关键词PostgreSQL、JSONB、数组遍历、键值遍历、LATERAL JOIN、展开、实战一、写在前面在上一篇中我们讲了-和-提取单个值的用法。但在实际开发中我们经常需要遍历 JSON 数组或遍历 JSON 对象的所有键值对——比如把一个 JSON 数组拆成多行、把 JSON 对象的每个 key 展开成行。PostgreSQL 提供了一组强大的生成函数Generating Functions配合LATERAL JOIN可以实现各种循环遍历需求。本文系统讲解。二、核心函数一览函数作用输入输出jsonb_array_elements(jsonb)将 JSON 数组展开为多行JSON 数组每行一个数组元素jsonbjsonb_array_elements_text(jsonb)同上但返回文本JSON 数组每行一个文本值jsonb_each(jsonb)展开对象为多行key, valueJSON 对象每行(key: text, value: jsonb)jsonb_each_text(jsonb)同上但 value 返回文本JSON 对象每行(key: text, value: text)jsonb_object_keys(jsonb)提取对象的所有键名JSON 对象每行一个 keytextjsonb_array_length(jsonb)返回数组长度JSON 数组整数jsonb_typeof(jsonb)返回 JSON 值的类型任意 JSON文本object/array/string/number等三、基础环境准备sql复制-- 创建测试表 CREATE TABLE employees ( id SERIAL PRIMARY KEY, name VARCHAR(50), data JSONB ); -- 插入测试数据 INSERT INTO employees (name, data) VALUES (张三, {skills: [Java, Python, Go], meta: {age: 28, city: 北京, level: P6}, projects: [{name: 订单系统, role: 后端}, {name: 支付网关, role: 架构}]}), (李四, {skills: [C, Rust], meta: {age: 35, city: 上海, level: P7}, projects: [{name: 中间件, role: 核心开发}]}), (王五, {skills: [JavaScript], meta: {age: 22, city: 深圳, level: P5}, projects: []});四、遍历 JSON 数组jsonb_array_elements4.1 基本用法数组展开为多行sql复制SELECT e.name, skill AS skill_value FROM employees e, jsonb_array_elements(e.data-skills) AS skill;结果nameskill_value张三Java张三Python张三Go李四C李四Rust王五JavaScript⚠️jsonb_array_elements返回的是 jsonb 类型所以值带双引号。4.2 取文本值jsonb_array_elements_textsql复制SELECT e.name, skill AS skill_text FROM employees e, jsonb_array_elements_text(e.data-skills) AS skill;结果nameskill_text张三Java张三Python张三Go李四C李四Rust王五JavaScript✅ 用jsonb_array_elements_text直接返回文本不带引号更方便后续使用。4.3 加序号展开数组并保留原始索引PostgreSQL 原生函数不直接返回索引可以用WITH ORDINALITYsql复制SELECT e.name, skill.skill AS skill_value, skill.ordinality AS skill_index FROM employees e, jsonb_array_elements(e.data-skills) WITH ORDINALITY AS skill(skill, ordinality);结果nameskill_valueskill_index张三Java1张三Python2张三Go3李四C1李四Rust2王五JavaScript1WITH ORDINALITY是 PostgreSQL 9.4 特性自动生成行号从 1 开始。这是很多人不知道的隐藏用法。五、遍历 JSON 对象jsonb_each/jsonb_object_keys5.1 展开对象所有键值对jsonb_eachsql复制SELECT e.name, kv.key AS meta_key, kv.value AS meta_value FROM employees e, jsonb_each(e.data-meta) AS kv;结果namemeta_keymeta_value张三age28张三city北京张三levelP6李四age35李四city上海李四levelP7王五age22王五city深圳王五levelP55.2 取文本值jsonb_each_textsql复制SELECT e.name, kv.key AS meta_key, kv.value AS meta_value_text FROM employees e, jsonb_each_text(e.data-meta) AS kv;结果value 不带引号namemeta_keymeta_value_text张三age28张三city北京张三levelP6.........5.3 只取键名jsonb_object_keyssql复制SELECT e.name, jsonb_object_keys(e.data-meta) AS meta_key FROM employees e;结果namemeta_key张三age张三city张三level李四age......适合场景不确定 JSON 有哪些 key需要动态获取所有键名。六、LATERAL JOIN 详解6.1 什么是 LATERAL JOINLATERAL关键字允许子查询引用左侧表的列。PostgreSQL 中生成函数如jsonb_array_elements放在 FROM 子句中时默认就是 LATERAL 行为不需要显式写LATERAL。但显式写出LATERAL可以让意图更清晰sql复制-- 隐式 LATERAL等价写法 SELECT e.name, skill FROM employees e, jsonb_array_elements(e.data-skills) AS skill; -- 显式 LATERAL更清晰的写法 SELECT e.name, skill FROM employees e CROSS JOIN LATERAL jsonb_array_elements(e.data-skills) AS skill;6.2 LATERAL JOIN 的优势可以加 WHERE 条件sql复制-- 只展开张三的技能 SELECT e.name, skill FROM employees e CROSS JOIN LATERAL jsonb_array_elements_text(e.data-skills) AS skill WHERE e.name 张三;6.3 配合 LEFT JOIN 处理空数组CROSS JOIN在数组为空时会丢失整行。用LEFT JOIN LATERAL ... ON true保留主表行sql复制SELECT e.name, proj-name AS project_name, proj-role AS project_role FROM employees e LEFT JOIN LATERAL jsonb_array_elements(e.data-projects) AS proj ON true;结果nameproject_nameproject_role张三订单系统后端张三支付网关架构李四中间件核心开发王五NULLNULL✅ 王五的 projects 为空数组[]用LEFT JOIN LATERAL保留了行项目信息为 NULL。这在报表统计中非常重要。七、实战场景场景 1统计每个技能被多少人掌握sql复制SELECT skill AS skill_name, COUNT(*) AS user_count FROM employees e, jsonb_array_elements_text(e.data-skills) AS skill GROUP BY skill ORDER BY user_count DESC;结果skill_nameuser_countJava1Python1Go1C1Rust1JavaScript1场景 2展开嵌套数组中的对象sql复制-- 展开每个员工的 projects 数组取出项目名和角色 SELECT e.name, proj-name AS project_name, proj-role AS project_role FROM employees e, jsonb_array_elements(e.data-projects) AS proj;结果nameproject_nameproject_role张三订单系统后端张三支付网关架构李四中间件核心开发场景 3行转列pivotsql复制-- 把 meta 对象展开为列 SELECT e.name, meta_kv-age AS age, meta_kv-city AS city, meta_kv-level AS level FROM employees e CROSS JOIN LATERAL (SELECT e.data-meta AS meta_kv) AS t;更优雅的方式直接用-sql复制SELECT name, data-meta-age AS age, data-meta-city AS city, data-meta-level AS level FROM employees; 当 key 固定已知时直接用-提取更简洁。jsonb_each适合 key 不固定或需要动态遍历的场景。场景 4多层嵌套遍历sql复制-- 遍历每个员工每个项目的每个键值对 SELECT e.name, proj-name AS project_name, kv.key, kv.value FROM employees e, jsonb_array_elements(e.data-projects) AS proj, jsonb_each(proj) AS kv;结果nameproject_namekeyvalue张三订单系统name订单系统张三订单系统role后端张三支付网关name支付网关张三支付网关role架构李四中间件name中间件李四中间件role核心开发场景 5动态遍历未知结构 JSONsql复制-- 递归遍历用 jsonb_typeof 判断类型决定是否继续展开 SELECT e.name, key, value, jsonb_typeof(value) AS value_type FROM employees e, jsonb_each(e.data) AS kv(key, value) WHERE jsonb_typeof(value) IN (string, number);结果namekeyvaluevalue_type张三skills[Java,Python,Go]array (被过滤掉)张三meta{age:28,...}object (被过滤掉)张三projects[{name:...}]array (被过滤掉)用jsonb_typeof可以动态判断每个值的类型配合 CASE WHEN 实现灵活遍历逻辑。八、性能优化建议8.1 GIN 索引加速包含查询sql复制CREATE INDEX idx_emp_data ON employees USING GIN (data); -- 走索引的查询 SELECT name FROM employees WHERE data {skills: [Java]};8.2 避免对大 JSON 做全量展开sql复制-- ❌ 慢全量展开 10 万行的大数组 SELECT name, skill FROM employees, jsonb_array_elements_text(data-skills); -- ✅ 快先过滤再展开 SELECT name, skill FROM employees, jsonb_array_elements_text(data-skills) AS skill WHERE id IN (SELECT id FROM employees WHERE data {skills: [Java]});8.3 数组长度判断sql复制-- 只展开数组长度 2 的记录 SELECT e.name, skill FROM employees e, jsonb_array_elements_text(e.data-skills) AS skill WHERE jsonb_array_length(e.data-skills) 1;九、常见坑 注意事项坑说明解决方案空数组丢失行jsonb_array_elements([]::jsonb)返回 0 行CROSS JOIN 会丢掉主表行用LEFT JOIN LATERAL ... ON trueNULL 字段报错jsonb_array_elements(NULL::jsonb)返回 NULL不报错但 CROSS JOIN 丢行先COALESCE(data-skills, []::jsonb)兜底非 JSON 数组传入jsonb_array_elements({a:1}::jsonb)报错cannot extract elements from an object先用jsonb_typeof()判断是否为 array_text后缀混淆jsonb_each返回 value 是 jsonbjsonb_each_text返回 text根据需要选择文本值用_text版本WITH ORDINALITY语法必须放在表函数后面func() WITH ORDINALITY AS t(col, idx)注意 ORDINALITY 列从 1 开始字段不是 JSONB-只能用于 json/jsonb 类型先::jsonb转换(data_text::jsonb)-key十、速查表需求函数/写法示例展开数组为多行JSONjsonb_array_elementsjsonb_array_elements(data-skills)展开数组为多行文本jsonb_array_elements_textjsonb_array_elements_text(data-skills)展开数组序号... WITH ORDINALITYjsonb_array_elements(data-skills) WITH ORDINALITY AS t(val, idx)展开对象键值对JSONjsonb_eachjsonb_each(data-meta) AS kv(key, value)展开对象键值对文本jsonb_each_textjsonb_each_text(data-meta) AS kv(key, value)只取对象键名jsonb_object_keysjsonb_object_keys(data-meta)获取数组长度jsonb_array_lengthjsonb_array_length(data-skills)判断 JSON 类型jsonb_typeofjsonb_typeof(data-skills)→array保留空数组行LEFT JOIN LATERAL ... ON true见 6.3 节总结遍历场景推荐函数返回值类型遍历数组元素jsonb_array_elements_texttext推荐遍历数组序号jsonb_array_elementsWITH ORDINALITYjsonb int遍历对象键值jsonb_each_texttext, text只取对象键名jsonb_object_keystext空数组保留行LEFT JOIN LATERAL ... ON true—多层嵌套遍历链式jsonb_array_elementsjsonb_each组合最佳实践数组遍历优先用jsonb_array_elements_text直接拿文本空数组/NULL 字段用LEFT JOIN LATERAL ... ON true或COALESCE兜底需要序号用WITH ORDINALITY很多人不知道这个隐藏特性大数据量先WHERE过滤再展开避免全表jsonb_array_elements包含查询走 GIN 索引不要用-做全表扫描

相关新闻

东方甄选俞敏洪,董宇辉与辉同行,同时在“去个人化“

东方甄选俞敏洪,董宇辉与辉同行,同时在“去个人化“

利润暴涨90倍,却没了最能带货的人 东方甄选近期发布的业绩预告,在舆论场里堪称一场"商业奇迹":利润同比暴涨近90倍。人们纷纷赞扬俞敏洪的人格魅力与战略定力。但拨开情绪,这件事真正值得讨论的,不是俞敏洪是…

2026/8/9 10:30:46 阅读更多 →
LinkSwift:网盘直链下载助手的终极使用指南

LinkSwift:网盘直链下载助手的终极使用指南

LinkSwift:网盘直链下载助手的终极使用指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘 / 迅雷…

2026/8/9 10:30:46 阅读更多 →
Vue+SpringBoot智能交通管控系统开发实践

Vue+SpringBoot智能交通管控系统开发实践

1. 项目背景与核心需求交通管理系统作为现代城市基础设施的重要组成部分,其智能化升级已成为必然趋势。传统交通管理系统往往存在响应速度慢、数据可视化程度低、系统扩展性差等问题。基于VueSpringBoot的技术栈构建的智能交通管控平台,正是为了解决这些…

2026/8/9 10:30:45 阅读更多 →

最新新闻

R语言核心语法与高效数据处理技巧详解

R语言核心语法与高效数据处理技巧详解

1. R语言基础语法精要解析 作为统计计算领域的瑞士军刀,R语言凭借其强大的数据处理能力和丰富的扩展包生态,已成为数据科学家的标配工具。今天我将结合多年实战经验,系统梳理R语言的核心语法要点,特别是那些官方文档不会明说但实际…

2026/8/9 11:27:15 阅读更多 →
如何彻底解决macOS鼠标体验问题?Mac Mouse Fix终极指南

如何彻底解决macOS鼠标体验问题?Mac Mouse Fix终极指南

如何彻底解决macOS鼠标体验问题?Mac Mouse Fix终极指南 【免费下载链接】mac-mouse-fix Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad! 项目地址: https://gitcode.com/GitHub_Trending/ma/mac-mouse-fix 你是否厌倦了在macOS上使用普…

2026/8/9 11:27:15 阅读更多 →
图书信息站架构设计与Elasticsearch搜索优化实践

图书信息站架构设计与Elasticsearch搜索优化实践

1. 项目背景与核心需求 "静思书屋"这个项目名称本身就透露着对阅读体验的极致追求。作为一个图书信息站,它需要处理海量的图书元数据、用户交互和搜索请求,同时还要保证页面加载速度和用户体验的流畅性。在实际开发中,我们遇到了几…

2026/8/9 11:27:15 阅读更多 →
redis中AOF 重写机制解析

redis中AOF 重写机制解析

AOF(Append Only File)持久化机制通过记录所有写命令来保证数据安全,但随之而来的问题是:随着运行时间增长,AOF 文件会不断膨胀。假设你反复对一个 key 执行 INCR 操作 1000 次,AOF 文件中会记录 1000 条 I…

2026/8/9 11:27:15 阅读更多 →
OpenCore Legacy Patcher完全指南:让老旧Mac焕发新生的终极免费工具

OpenCore Legacy Patcher完全指南:让老旧Mac焕发新生的终极免费工具

OpenCore Legacy Patcher完全指南:让老旧Mac焕发新生的终极免费工具 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 还在为老旧Mac无法升级最新ma…

2026/8/9 11:27:15 阅读更多 →
山海万灵 HarmonyOS 文化知识设计续篇(23):发布候选、灰度、回滚与观察期门禁

山海万灵 HarmonyOS 文化知识设计续篇(23):发布候选、灰度、回滚与观察期门禁

一次内容更新可能同时改变图鉴正文、神兽关系、讲解提示词和客户端展示。若这些变化只靠“打一个新包、发布一批内容”分别推进,出现异常时很难判断该停掉应用版本、撤回内容,还是切回讲解策略。更稳妥的做法,是把它们收束为一份可追溯的发布…

2026/8/9 11:26:15 阅读更多 →

日新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/9 0:01:47 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/9 0:01:47 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/9 0:03:48 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/9 0:01:47 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/9 0:01:47 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/9 0:03:48 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/8 17:02:44 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/9 0:45:04 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/8 17:02:44 阅读更多 →