hive中没有group_concat

Hive 分组拼接:collect_set + concat_ws,替代 MySQL 的 group_concat

在 MySQL 里,group_concat 是一个很常用的函数——按某个字段分组,把组内另一个字段的值用逗号拼成一行。

比如:

SELECT doc_id, GROUP_CONCAT(name) FROM table GROUP BY doc_id;

结果可能是:

doc_001 | 分类1,分类2,分类3

但 Hive 里没有 group_concat

Hive 的替代方案是两步走:

  1. collect_set / collect_list:把同组的多行聚合成一个数组
  2. concat_ws:把数组用分隔符拼成字符串
concat_ws(',', collect_set(列名))  -- 相当于 group_concat

两个函数的分工

函数 做什么 去重
collect_set(列) 同组的多行聚合成一个数组 去重
collect_list(列) 同组的多行聚合成一个数组 保留重复
concat_ws('分隔符', 数组) 把数组元素拼成一个字符串

组合方式:

concat_ws(',', collect_set(列名))   -- 去重拼接
concat_ws(',', collect_list(列名))  -- 不去重拼接

一个实际的例子:文档的分类拼接

需求: 有一张文档分类关联表,一个文档可以属于多个分类。现在要按 doc_id 分组,把每个文档的所有分类名称拼成一行。

数据:

doc_id category_name
doc_001 技术
doc_001 人工智能
doc_001 技术 ← 重复了
doc_002 设计
doc_002 UI/UX

SQL(去重拼接):

SELECT 
    doc_id,
    concat_ws(',', collect_set(category_name)) AS categories
FROM doc_category
GROUP BY doc_id;

结果:

doc_id categories
doc_001 技术,人工智能
doc_002 设计,UI/UX

doc_001 里有三个分类,但”技术”出现了两次,collect_set 去重后只剩两个。

如果不去重(collect_list):

concat_ws(',', collect_list(category_name))

结果会变成:

doc_id categories
doc_001 技术,人工智能,技术

进阶:拼接多个字段

如果要拼接的是 name:id 这种格式:

SELECT 
    doc_id,
    concat_ws(';', collect_set(concat(name, ':', id))) AS name_id_list
FROM table
GROUP BY doc_id;

结果:分类1:1;分类2:2;分类3:3

进阶:排序后再拼接

collect_setcollect_list 的顺序是不确定的。如果要按某个字段排序:

SELECT 
    doc_id,
    concat_ws(',', sort_array(collect_set(name))) AS sorted_names
FROM table
GROUP BY doc_id;

sort_array 按字典序排序。如果需要自定义排序规则(比如按数字大小),用 sort_array(collect_set(name), false) 可改为降序。