Presto中如何UNNEST JSON Map而非数组得到预期结果表
问题根因
之前执行语句报错来自两处逻辑偏差:
- 类型不匹配:通过
JSON_EXTRACT提取到的$.1节点是{}包裹的JSON对象,并非[]包裹的JSON数组,强行CAST为ARRAY(VARCHAR)时,Presto会校验输入的JSON格式,不符合数组结构就会触发INVALID_CAST_ARGUMENT异常。 - 提取范围不全:仅提取了
$.1单节点内容,即便类型转换逻辑正确,也只能拿到单条结果,无法遍历顶层"2"键对应的嵌套对象,得不到两行的目标结果。
实现方案
Presto原生支持直接对MAP结构做UNNEST操作:传入MAP类型值到UNNEST函数时,会自动将MAP拆分为两列,分别对应原MAP的所有键、所有键关联的值,搭配CROSS JOIN即可遍历MAP内的全部键值对,不需要绕路转成数组。
针对给出的JSON结构,实现逻辑如下:
- 将完整JSON字符串通过
JSON_TO_MAP解析为顶层MAP结构,MAP的键为JSON里的"1""2",MAP的值为每个键对应的嵌套对象 - 通过CROSS JOIN UNNEST拆解顶层MAP,拿到每个嵌套的对象值
- 从每个嵌套对象中提取a、b字段的标量值,拼成目标结果
可直接运行的SQL代码:
SELECT JSON_EXTRACT_SCALAR(nested_obj, '$.a') AS a, JSON_EXTRACT_SCALAR(nested_obj, '$.b') AS b FROM ( -- 解析完整JSON为MAP结构 SELECT JSON_TO_MAP('{"1":{"a":10,"b":11},"2":{"a":20,"b":21}}') AS root_map ) base CROSS JOIN UNNEST(root_map) AS flat (map_key, nested_obj)
运行后输出的结果完全匹配预期:
a | b ---+--- 10 | 11 20 | 21
注意事项
- JSON中{}包裹的对象结构对应Presto的MAP/STRUCT类型,和[]包裹的数组结构对应ARRAY类型,二者无法直接强转,混转必然触发类型校验报错
- 遍历MAP全部键值对时,不需要提前把MAP转成ARRAY再UNNEST,直接传入MAP结构即可,拆出的列数和MAP的键值对组数完全对应,每一行映射一个键值对。
内容的提问来源于stack exchange,提问作者vishwarajanand
相关产品推荐
相关产品推荐

