SQL大厂真题-互相关注
现有用户关注者列表记录表 t_user_follower,包含两个字段:follower_ids:关注者列表,里面存的是该用户关注的用户 ID,以逗号分隔lateral view explode():follower_ids 是一个用逗号分隔的字符串列表,需要先用列转行(炸裂函数)把它展开成多行concat_ws():字符串拼接函数,用来把两个用户 ID 按统一顺序拼接成一个标识核心思路是:把“A 关注 B”和“B 关注 A”这两条记录,通过排序拼接,变成完全相同的字符串,这样它们就会落到同一个分组里。如果某个拼接结果出现了 2 次,就说明这两个用户互相关注;只出现 1 次,说明是单向关注。Step 1:炸裂 follower_ids,转换成多行select user_id, follower_ids, follower_idfrom t_user_followerlateral view explode(split(follower_ids, ',')) t as follower_id这一步把“一对多”的关注关系,拆成了一行一个“关注对”。Step 2:有序拼接 user_id 和 follower_idselect 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,这样原本看起来不相关的两行,就产生了关联。可以看到,0001→0002 和 0002→0001 这两条记录的 friend 字段完全相同。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) = 2group by friend 之后,互相关注的用户对会被聚到同一组里,出现 2 次;单向关注只会出现 1 次。用 having count(1) = 2 过滤,就只剩下真正互相关注的用户对。结合样例数据可以验证:0001 的关注列表里有 0002,0002 的关注列表里也有 0001,所以 0001 和 0002 互相关注;而 0003 只被 0001、0002 单向关注,0004 也是单向关注关系,不满足互相关注的条件。-- 建表语句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)是一个很通用的模板,除了互相关注,还能用在“互相点赞”“互相转账核对”这类双向关系判断的题目上,遇到类似场景可以直接套用。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至23467321@qq.com举报,一经查实,本站将立刻删除;如已特别标注为本站原创文章的,转载时请以链接形式注明文章出处,谢谢!