如何在保留product_id列的同时,按user_id和order_date聚合生成数组列?
问题
假设您有一组购买数据如下:
| user_id | order_date | product_id |
|---|---|---|
| 001 | mon | 2e1 |
| 001 | mon | 44h |
| 001 | tues | e6f |
| 002 | wed | 6g3 |
| 002 | wed | 43m |
| 003 | wed | k19 |
| 003 | fri | 9d5 |
需要按user_id和order_date分组,使用COLLECT_SET将product_id聚合为一个数组列product_ids,同时保留原product_id列,期望得到如下结果:
| user_id | order_date | product_id | product_ids |
|---|---|---|---|
| 001 | mon | 2e1 | ["2e1","44h"] |
| 001 | mon | 44h | ["2e1","44h"] |
| 001 | tues | e6f | ["e6f"] |
| 002 | wed | 6g3 | ["6g3","43m"] |
| 002 | wed | 43m | ["6g3","43m"] |
| 003 | wed | k19 | ["k19"] |
| 003 | fri | 9d5 | ["9d5"] |
遇到的问题
可以通过以下查询创建数组列,但无法保留每一行的product_id列:
SELECT user_id, order_date, COLLECT_SET(product_id) AS product_ids FROM table t GROUP BY user_id, order_date
如果将product_id加入查询并分组,product_ids列将始终是长度为1的数组:
SELECT user_id, order_date, product_id, COLLECT_SET(product_id) AS product_ids FROM table t GROUP BY user_id, order_date, product_id
示例结果:
| user_id | order_date | product_id | product_ids |
|---|---|---|---|
| 001 | mon | 2e1 | ["2e1"] |
| 001 | mon | 44h | ["44h"] |
若在GROUP BY中排除product_id,会报错:Expression not in GROUP BY key 'product_id'
是否可以通过单个简单查询实现需求,无需创建临时表再按user_id和order_date进行关联?
解决方案
可以使用窗口函数实现需求,无需分组聚合或临时表关联。通过OVER (PARTITION BY user_id, order_date)子句,将COLLECT_SET的计算范围限定在每个user_id + order_date组内,同时保留原表的每一行数据:
SELECT user_id, order_date, product_id, COLLECT_SET(product_id) OVER (PARTITION BY user_id, order_date) AS product_ids FROM table t
这个查询会直接返回符合预期的结果:
- 同一
user_id和order_date的所有行,product_ids列会返回相同的集合数组 - 完整保留原
product_id列的每一行数据
这种方式避免了分组导致的行压缩,也不需要额外的关联操作,是最简洁的实现方式。
内容的提问来源于stack exchange,提问作者Ben Nouhan
相关产品推荐
相关产品推荐

