SQL大厂真题-互相关注

四季读书网 5 0
SQL大厂真题-互相关注
1. 题目
现有用户关注者列表记录表 t_user_follower,包含两个字段:
user_id:用户 ID
follower_ids:关注者列表,里面存的是该用户关注的用户 ID,以逗号分隔
要求:找出互相关注的用户对。
2. 考点
这道题主要考察三个知识点:
lateral view explode():follower_ids 是一个用逗号分隔的字符串列表,需要先用列转行(炸裂函数)把它展开成多行
concat_ws():字符串拼接函数,用来把两个用户 ID 按统一顺序拼接成一个标识
if():根据条件判断,决定拼接顺序
3. 解题思路
核心思路是:把“A 关注 B”和“B 关注 A”这两条记录,通过排序拼接,变成完全相同的字符串,这样它们就会落到同一个分组里。如果某个拼接结果出现了 2 次,就说明这两个用户互相关注;只出现 1 次,说明是单向关注。
SQL大厂真题-互相关注-第1张图片-四季读书网
图 1 互相关注问题的三步求解思路
Step 1:炸裂 follower_ids,转换成多行
select    user_id,    follower_ids,    follower_idfrom t_user_followerlateral view explode(split(follower_ids, ',')) t as follower_id
执行结果:
user_id
follower_ids
follower_id
0001
0002,0003
0002
0001
0002,0003
0003
0002
0001,0003
0001
0002
0001,0003
0003
0003
0004
0004
0004
0001,0002
0001
0004
0001,0002
0002
这一步把“一对多”的关注关系,拆成了一行一个“关注对”。
Step 2:有序拼接 user_id 和 follower_id
select    user_id,    follower_id,    if(user_id < follower_id,       concat_ws(',', user_id, follower_id),       concat_ws(',', follower_id, user_id)) as friend,    follower_idsfrom t_user_followerlateral view explode(split(follower_ids, ',')) t as follower_id
关键就在 if() 这一步:无论是“0001 关注 0002”还是“0002 关注 0001”,拼接后都会统一变成 0001,0002,这样原本看起来不相关的两行,就产生了关联。
执行结果(节选):
user_id
follower_id
friend
0001
0002
0001,0002
0002
0001
0001,0002
0001
0003
0001,0003
0004
0001
0001,0004
可以看到,0001→0002 和 0002→0001 这两条记录的 friend 字段完全相同。
Step 3:按拼接字符串分组统计
select    friendfrom    (        select            user_id,            follower_ids,            follower_id,            if(user_id < follower_id,               concat_ws(',', user_id, follower_id),               concat_ws(',', follower_id, user_id)) as friend        from t_user_follower        lateral view explode(split(follower_ids, ',')) t as follower_id    ) ttgroup by friendhaving count(1) = 2
group by friend 之后,互相关注的用户对会被聚到同一组里,出现 2 次;单向关注只会出现 1 次。用 having count(1) = 2 过滤,就只剩下真正互相关注的用户对。
执行结果:
friend
0001,0002
结合样例数据可以验证:0001 的关注列表里有 0002,0002 的关注列表里也有 0001,所以 0001 和 0002 互相关注;而 0003 只被 0001、0002 单向关注,0004 也是单向关注关系,不满足互相关注的条件。
4. 建表语句
-- 建表语句create table t_user_follower(    user_id      string comment '用户id',    follower_ids string comment '关注者列表');-- 数据插入语句insert into t_user_follower values('0001', '0002,0003'),('0002', '0001,0003'),('0003', '0004'),('0004', '0001,0002');
这类“自关联去重判重”的解法(排序拼接 + group by + count)是一个很通用的模板,除了互相关注,还能用在“互相点赞”“互相转账核对”这类双向关系判断的题目上,遇到类似场景可以直接套用。

抱歉,评论功能暂时关闭!