PostgreSQL中用jsonb_array_elements()展开JSON数组最直接,但仅支持jsonb类型,需显式转换;MySQL用JSON_TABLE()、SQL Server用OPENJSON(),三者语法不兼容且空值处理策略不同。

PostgreSQL 中用 jsonb_array_elements() 展开 JSON 数组
PostgreSQL 的 jsonb_array_elements() 是最直接的展开方式,它把每个数组元素转成一行。注意它只接受 jsonb 类型,如果字段是 json,得先显式转换:jsonb_array_elements(data::jsonb)。别用 json_array_elements()——它不支持嵌套对象或 null 元素,容易在遇到空值时报错 cannot call json_array_elements on a null。
常见错误是直接在 WHERE 或 GROUP BY 里引用展开后的别名,但 SQL 执行顺序决定了必须用子查询或 CTE 包一层:
SELECT tag, COUNT(*) FROM ( SELECT jsonb_array_elements(tags::jsonb)->>'name' AS tag FROM products ) t GROUP BY tag;
MySQL 8.0+ 用 JSON_TABLE() 实现等价展开
MySQL 没有类似 jsonb_array_elements() 的函数,JSON_TABLE() 是唯一可靠方案。它需要显式定义列名和类型,且路径必须指向数组(如 $[*]),不能写成 $ 或 $.items(除非你确定 items 字段存在且是数组)。
关键点:如果原 JSON 字段为 NULL 或非数组,JSON_TABLE() 默认返回空结果集(不是报错),所以统计时会“丢失”整条记录。若需保留,得提前用 IFNULL() 或 CASE 补默认空数组:
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
JSON_TABLE(IFNULL(meta, '[]'), '$[*]' COLUMNS (score INT PATH '$.score')) AS jt- 路径中用
$.score提取数值,$.score[0]这类写法会失败——JSON_TABLE不支持多层下标嵌套解析 - 性能上,
JSON_TABLE()比 PostgreSQL 的展开慢不少,尤其数组长、行数多时,建议对源表加覆盖索引(如ALTER TABLE logs ADD COLUMN tags_json JSON; CREATE INDEX idx_tags ON logs (tags_json));)
SQL Server 用 OPENJSON() 并指定 WITH 子句
OPENJSON() 必须配合 WITH 显式声明字段结构,否则只返回键值对的通用表,无法直接分组。例如字段存的是 [{"id":1,"type":"A"},{"id":2,"type":"B"}],就得写:
SELECT type, COUNT(*) FROM logs CROSS APPLY OPENJSON(tags) WITH (type VARCHAR(20) '$.type') GROUP BY type;
容易踩的坑:
- 没写
WITH就直接SELECT * FROM OPENJSON(tags)→ 返回三列key/value/type,根本没法按业务字段分组 -
tags是NVARCHAR(MAX)但内容不是合法 JSON → 报错JSON text is not properly formatted,得先用ISJSON(tags) = 1过滤 - 数组为空
[]时,OPENJSON()返回零行,该记录在分组中消失;想保留需用OUTER APPLY+ISNULL()补默认值
跨数据库兼容性差,别指望一条 SQL 跑通
三个主流数据库的 JSON 展开语法完全不兼容:jsonb_array_elements()、JSON_TABLE()、OPENJSON() 互不可替换。即使都支持标准 JSON 函数(如 JSON_EXTRACT()),也没提供数组“炸裂”能力。如果应用需多库部署,要么在应用层解析(比如 Python 用 json.loads() + itertools.chain.from_iterable()),要么统一用视图封装,把展开逻辑下沉到各库的存储过程里。
真正麻烦的不是语法差异,而是 null 处理策略不一致:PostgreSQL 展开 null 数组报错,MySQL 返回空集,SQL Server 需手动 ISJSON() 判断——同一份脏数据,在不同库上分组结果可能行数都不一样。

















