一、题目
有用户账户表:包含年份,用户id和余额。请按照年份分组,取出余额前两小和前两大对应的用户id。**注意:**需要保持余额最小和最大的用户id排首位。

二、思路
1、计算每年 每个用户余额的升序排名和降序排名。升序排名前两名就是余额前两小的用户,降序排名前两名就是前两大的用户。可以使用row_number实现。

2、取每年余额最小的两个用户。可以使用collect_list实现行转列
3、取每年余额最大的两个用户。
4、最后使用年份关联。
三、解答
with tab_detail as (
-- 1、计算每年 每个用户余额的升序排名和降序排名。升序排名前两名就是余额前两小的用户,降序排名前两名就是前两大的用户。可以使用row_number实现。
select
year,
user_id,
value,
row_number() over(partition by year order by value) asc_rn, -- 升序
row_number() over(partition by year order by value desc) dasc_rn -- 降序
from user_account_amount
)
select
t11.year,
userids_min,
userids_max
from (
-- 2、取每年余额最小的两个用户。可以使用collect_list实现行转列
select
year,
concat_ws(',', collect_list(user_id)) userids_min
from (
select
year,
user_id
from tab_detail
where asc_rn <= 2
order by asc_rn
) t01
group by year
) t11
left join (
-- 3、取每年余额最大的两个用户。
select
year,
concat_ws(',', collect_list(user_id)) userids_max
from (
select
year,
user_id
from tab_detail
where dasc_rn <= 2
order by dasc_rn
) t01
group by year
) t12
on t11.year = t12.year结果:

数据
# 建表
--建表语句
create table if not exists user_account_amount(
year string,
user_id string,
value bigint
) comment '查询前2大和前2小用户并有序拼接'
stored as parquet
;
--插入数据
insert into user_account_amount(year, user_id, value)
values ('2022', 'A', 30),
('2022', 'B', 10),
('2022', 'C', 20),
('2023', 'A', 40),
('2023', 'B', 50),
('2023', 'C', 20),
('2023', 'D', 30);注:题目获取自网络
评论