JSON_TABLE是MySQL 8.0.14+将JSON数组展开为多行关系表的唯一原生函数,必须在FROM子句中使用$[*]路径匹配数组元素,配合COLUMNS提取字段,不可用JSON_EXTRACT替代。

MySQL 8.0+ 怎么用 JSON_TABLE 把 JSON 字段展开成行
MySQL 8.0.14 起才支持 JSON_TABLE,这是最直接的解法。它能把嵌套 JSON 当作“虚拟表”来 JOIN,不用写一堆 JSON_EXTRACT。
常见错误是把路径写成 $.items[0].name 这种固定下标——这只能取第一个,实际要展开数组得用 $[*]。
- 路径必须用
$[*](匹配数组所有元素)或$(匹配整个 JSON)开头,否则解析失败 -
COLUMNS子句里用FOR ORDINALITY可以加序号列,方便调试顺序 - 如果 JSON 字段为
NULL或格式非法,整行会静默丢弃,建议先用JSON_VALID()过滤
SELECT u.id, jt.name, jt.price FROM users u, JSON_TABLE(u.preferences, '$.cart.items[*]' COLUMNS ( name VARCHAR(50) PATH '$.product_name', price DECIMAL(10,2) PATH '$.amount' )) AS jt WHERE JSON_VALID(u.preferences);
PostgreSQL 怎么用 jsonb_to_recordset 展开数组字段
PostgreSQL 的 jsonb_to_recordset 更灵活,但要求你显式声明返回列的类型和名字,不能靠推断。
容易踩的坑是:输入 JSON 必须是数组([{...}, {...}]),不是对象({...})。如果源字段是单个对象,得先包一层 ARRAY[the_json]。
- 列名必须和 JSON 键名完全一致(区分大小写),否则值为
NULL - 如果某条记录里某个键缺失,对应列就是
NULL,不会报错 - 性能上,
jsonb_to_recordset比多次->>提取快,尤其字段多时
SELECT u.id, jt.name, jt.price FROM users u, jsonb_to_recordset(u.preferences->'cart'->'items') AS jt( name TEXT, price NUMERIC ) WHERE u.preferences ? 'cart';
SQL Server 怎么用 OPENJSON 配合 WITH 子句做映射
SQL Server 的 OPENJSON 是唯一能直接把 JSON 数组转成结果集的函数,但必须配 WITH 显式定义 schema。
最常出错的是路径写法:$.cart.items 是对的,但写成 $.cart.items[*] 就会报错——SQL Server 不支持这种通配语法,数组路径本身就隐含了展开语义。
-
WITH里的列名不一定要和 JSON 键名相同,可以用别名,但类型必须匹配(比如 JSON 字符串不能映射到INT) - 如果 JSON 中有 null 值,默认映射为 SQL
NULL;想转成默认值,得在WITH里加DEFAULT子句 - 没加
WITH直接调OPENJSON(json)只返回键/值/类型三列,没法直接当业务表用
SELECT u.id, jt.name, jt.price
FROM users u
CROSS APPLY OPENJSON(u.preferences, '$.cart.items')
WITH (
name VARCHAR(50) '$.product_name',
price DECIMAL(10,2) '$.amount'
) AS jt
WHERE ISJSON(u.preferences) = 1;
跨数据库兼容性差在哪?关键差异点总结
没有通用语法。MySQL 依赖 JSON_TABLE(8.0+),PostgreSQL 用 jsonb_to_recordset(9.4+),SQL Server 用 OPENJSON(2016+)。低版本只能靠应用层解析或触发器预拆分。
最容易被忽略的是空值和结构变异处理:同一个 JSON 字段,有的记录是 {"items":[]},有的是 {"items":null},有的干脆缺 key——三种情况在各数据库中表现不同,有的返回空集,有的报错,有的静默跳过。
真正上线前,得拿真实数据样本覆盖这三类边界,而不是只测“理想 JSON”。


















