SQL 如何用 LATERAL VIEW explode 处理 Hive/Presto 中的数组列

1次阅读

LATERAL VIEW explode() 在 hive 和 Presto 中行为不一致,因 Hive 基于 UDTF 模型依赖该语法,而 Presto 采用标准 sql 的 UNNEST 语义,不支持 LATERAL VIEW,必须用 CROSS JOIN UNNEST 替代,且需处理 NULL 安全性与语义差异。

SQL 如何用 LATERAL VIEW explode 处理 Hive/Presto 中的数组列

为什么 LATERAL VIEW explode() 在 Hive 和 Presto 中行为不一致

Hive 支持 LATERAL VIEW explode(),Presto(现 Trino)完全不支持该语法,直接报错 line x:xx: mismatched input 'LATERAL'。这不是写法问题,是语法层面的割裂:Hive 基于 mapreduce/Tez 的 UDTF 模型依赖 LATERAL VIEW,而 Presto 用的是标准 SQL 的 UNNEST 语义。强行套用 Hive 写法在 Presto 里必然失败。

Hive 中 LATERAL VIEW explode() 的正确写法和常见翻车点

核心是理解 LATERAL VIEW 必须配合 explode() 使用,且只能展开数组或 map;不能嵌套调用多个 explode() 到同一行(会笛卡尔爆炸),也不能对空数组或 NULL 直接展开(结果整行丢失)。

  • select id, name, item FROM src_table LATERAL VIEW explode(items) t AS item —— 正确:单数组展开,别名 t 可省略,但字段别名 item 必须有
  • 如果 items 是空数组或 NULL,该行不会出现在结果中;需提前用 array_size(items) > 0size(coalesce(items, array[])) > 0 过滤
  • 展开 map 时用 explode(map_col),会返回两列:keyvalue,写成 LATERAL VIEW explode(props) t AS k,v
  • 多个数组要分别展开?必须用多个 LATERAL VIEW,例如 LATERAL VIEW explode(tags) t1 AS tag LATERAL VIEW explode(scores) t2 AS score —— 注意这会产生笛卡尔积,不是 zip

Presto/Trino 中等价替代方案:用 UNNEST + CROSS JOIN

Presto 不认 LATERAL VIEW,但支持标准 SQL 的 UNNEST,且必须搭配 CROSS JOIN(或 LEFT JOIN 处理空数组)。关键区别在于:Hive 的 explode() 是函数式 UDTF,Presto 的 UNNEST 是关系操作符,语义更严格。

  • 基础等价写法:SELECT id, name, item FROM src_table CROSS JOIN UNNEST(items) AS t(item)
  • 处理 NULL 或空数组用 LEFT JOINSELECT id, name, item FROM src_table LEFT JOIN UNNEST(coalesce(items, Array[])) AS t(item) ON TRUE —— 这样原行保留,item 为 NULL
  • 展开 map:CROSS JOIN UNNEST(map_col) AS t(k,v),字段名 kv 需显式声明
  • 多个数组 zip?Presto 不支持原生 zip,得用 zip 函数预合成数组:CROSS JOIN UNNEST(zip(tags, scores)) AS t(tag,score)

跨引擎兼容写法难在哪?真正麻烦的是 NULL 安全性和语义对齐

不是语法替换就能跑通。Hive 的 explode() 对 NULL 数组静默跳过,Presto 的 UNNEST 遇到 NULL 直接报错(Cannot unnest null),必须用 coalesce(col, array[]) 拦截。更隐蔽的是:Hive 允许在 WHERE 中直接写 size(explode(items)) > 0(虽然逻辑错误),而 Presto 要求所有 UNNEST 出现在 FROM 子句,过滤必须移到 WHERE 或子查询里。这些细节不调,数据就少行或多 NULL。

text=ZqhQzanResources