精选·Hive与SQL

行转列、列转行分别怎么写?concat_ws、collect_list、lateral view 实战

91学AI·2026/7/13·9 阅读

考察点

行列转换是 Hive 手撕题的经典题型,面试官想看你熟不熟 collect 系列聚合函数和 lateral view 这对组合。追问方向:explode 多个字段怎么写、collect_list 和 collect_set 的区别、转成数组后怎么按位置取。

参考答案

行转列:多行聚成一行一列

场景:用户标签表一行一个标签,要聚合成一行用户、一列逗号分隔的标签串。

user_idtag
1运动
1美食
2读书

目标:1, 运动,美食2, 读书

select user_id,
       concat_ws(',', collect_set(tag)) as tags
from user_tag
group by user_id;

三个函数各司其职:

  • collect_set(col):聚合函数,把组内的值收成数组并去重
  • collect_list(col):同样收成数组但不去重,保留重复值。要保序或计数的场景用它。
  • concat_ws(sep, array):把数组按分隔符拼成字符串,自动跳过 null 元素。它的兄弟 concat 只能拼标量,遇到数组类型会报错,这是常踩的坑。

如果想按时间排序再拼接,Hive 2.x 之后可以在 collect 前排好序的子查询里做(外层聚合一般能保持顺序但不保证),更稳的写法是先把要拼的内容排好序收进结构里,或者用 sort_array(collect_list(...)) 显式排序。

列转行:一行拆成多行

场景正好反过来:一行里存着逗号分隔的标签串或数组,要炸开成多行。

select user_id, tag
from user_tag_wide
lateral view explode(split(tags, ',')) t as tag;

拆解一下这条语句的三个部分:

  • split(tags, ','):先把字符串切成数组。
  • explode(array):UDTF(表生成函数),输入一行一个数组,输出多行,每行一个元素。UDTF 和普通函数的本质区别是它改变行数,所以不能直接和别的列一起写在 select 里(老版本 Hive 会报错或行为异常)。
  • lateral view ... t as tag:侧视图把 UDTF 的输出和原表做类似笛卡尔展开的连接,让 explode 的多行结果能和原行其他列一起输出。t 是侧视图别名,tag 是炸开后的列名。

进阶:带位置的展开和多个数组

要保留元素在数组里的位置,用 posexplode

select user_id, idx, item
from t lateral view posexplode(items) t as idx, item;

一行里有两个等长数组要同步展开(比如商品 id 数组和对应价格数组),标准做法是多个 lateral view 串联:

select user_id, pid, price
from t
lateral view explode(pids) a as pid
lateral view explode(prices) b as price;

注意这种写法是两个数组的笛卡尔积,长度不等时会错配。严格对齐要用 posexplode 后按 idx join:

select a.user_id, a.item as pid, b.item as price
from (select user_id, idx, item from t lateral view posexplode(pids) x as idx, item) a
join (select user_id, idx, item from t lateral view posexplode(prices) x as idx, item) b
on a.user_id = b.user_id and a.idx = b.idx;

空值处理

explode 遇到空数组或 null,这一行直接消失(没有输出)。左表行数不能丢的场景用 lateral view outer explode(...),outer 关键字让空数组也输出一行(元素为 null)。统计 UV 类报表时忘了 outer,会把没有标签的用户漏掉,指标对不上往往就是这个原因。

性能提醒

collect_list 是把组内所有值收进单机的内存数组,单组值特别多(比如一个用户几百万条行为)时会 OOM,这种场景别做行转列,或者先截断。explode 是行数放大器,大表 explode 后行数翻几十倍,下游要注意 shuffle 量和分区设计。

可能的追问

  • collect_set 和 collect_list 怎么选? 要去重选 collect_set,要保留出现次数或原始顺序选 collect_list。collect_set 内部去重要建哈希表,单组值多的时候内存压力更大。
  • 行转列后想按某个字段排序拼接怎么办? 先子查询排序再 collect_list(不保证),稳妥做法是把排序键和值拼成 lpad(sort_key) + '_' + value 一起 collect 后 sort_array,再 regexp_replace 剥掉前缀。
  • explode 能不能直接写在 select 里不带 lateral view? Hive 0.13 之前部分版本支持但限制多,现代写法一律 lateral view,语义清晰且能和原表列组合输出。

评论 (0)

暂无评论,快来抢沙发吧!

91学AI

© 2026 91学AI · 按岗位学 AI 与大数据. All rights reserved.