腾讯大数据面试SQL-朋友圈点赞数Top N
⚠️ 待修正
一、题目背景
这道题来自腾讯微信事业群的数据分析岗面试。朋友圈是微信的核心社交功能,每天产生数十亿条内容和百亿级点赞。运营和产品团队需要快速识别"爆款朋友圈"——哪些用户的内容最能引发互动,哪些话题最受欢迎。
业务场景:朋友圈信息流的排序算法需要参考"内容质量分",点赞数Top N就是最直接的信号。产品经理也会关注"每个用户的Top朋友圈"来评估用户的社交影响力。这道SQL就是内容质量打分的基础查询。
二、题目
现有朋友圈表 t8_moments 和点赞表 t8_likes,请查询每个用户的朋友圈中,点赞数排名前2的朋友圈内容及点赞数。
朋友圈表 t8_moments:
+------------+----------+------------------------+---------------------+
| moment_id | user_id | content | post_time |
+------------+----------+------------------------+---------------------+
| 101 | 1 | 今天天气真好! | 2023-03-01 10:00:00 |
| 102 | 1 | 分享一首好听的歌 | 2023-03-01 12:00:00 |
| 103 | 2 | 周末去哪儿玩呢? | 2023-03-01 14:00:00 |
| 104 | 2 | 推荐一家很棒的餐厅 | 2023-03-02 09:00:00 |
| 105 | 3 | 打卡新开的咖啡店 | 2023-03-02 10:00:00 |
| 106 | 1 | 晚上加班中... | 2023-03-02 20:00:00 |
| 107 | 3 | 今天的日落真美 | 2023-03-03 18:00:00 |
+------------+----------+------------------------+---------------------+
点赞表 t8_likes:
+------------+---------------+---------------------+
| moment_id | like_user_id | like_time |
+------------+---------------+---------------------+
| 101 | 2 | 2023-03-01 10:05:00 |
| 101 | 3 | 2023-03-01 10:10:00 |
| 101 | 4 | 2023-03-01 10:15:00 |
| 101 | 5 | 2023-03-01 11:00:00 |
| 102 | 2 | 2023-03-01 12:30:00 |
| 102 | 3 | 2023-03-01 13:00:00 |
| 103 | 1 | 2023-03-01 14:30:00 |
| 103 | 3 | 2023-03-01 15:00:00 |
| 103 | 4 | 2023-03-01 16:00:00 |
| 104 | 1 | 2023-03-02 09:30:00 |
| 105 | 1 | 2023-03-02 10:30:00 |
| 105 | 2 | 2023-03-02 11:00:00 |
| 106 | 2 | 2023-03-02 20:30:00 |
| 107 | 1 | 2023-03-03 18:30:00 |
| 107 | 2 | 2023-03-03 19:00:00 |
| 107 | 4 | 2023-03-03 19:30:00 |
+------------+---------------+---------------------+
三、思路分析
本题需要查询每个用户朋友圈中点赞数排名前2的内容,核心步骤如下:
- 先统计每条朋友圈的点赞数;
- 关联朋友圈表获取朋友圈内容和所属用户;
- 使用 ROW_NUMBER() 按用户分组、按点赞数降序排名;
- 筛选排名前2的记录;
| 维度 | 评分 |
|---|---|
| 题目难度 | ⭐️⭐️⭐️ |
| 题目清晰度 | ⭐️⭐️⭐️⭐️⭐️ |
| 业务常见度 | ⭐️⭐️⭐️⭐️⭐️ |
四、逐步推导
1. 统计每条朋友圈的点赞数
执行SQL
select moment_id,
count(distinct like_user_id) as like_cnt
from t8_likes
group by moment_id
执行结果
+------------+----------+
| moment_id | like_cnt |
+------------+----------+
| 101 | 4 |
| 102 | 2 |
| 103 | 3 |
| 104 | 1 |
| 105 | 2 |
| 106 | 1 |
| 107 | 3 |
+------------+----------+
2. 关联朋友圈表获取内容和所属用户,按用户分组对点赞数排名
执行SQL
select m.user_id,
m.moment_id,
m.content,
t.like_cnt,
row_number() over (partition by m.user_id order by t.like_cnt desc) as rn
from t8_moments m
left join (
select moment_id,
count(distinct like_user_id) as like_cnt
from t8_likes
group by moment_id
) t on m.moment_id = t.moment_id
执行结果
+----------+------------+------------------------+----------+-----+
| user_id | moment_id | content | like_cnt | rn |
+----------+------------+------------------------+----------+-----+
| 1 | 101 | 今天天气真好! | 4 | 1 |
| 1 | 102 | 分享一首好听的歌 | 2 | 2 |
| 1 | 106 | 晚上加班中... | 1 | 3 |
| 2 | 103 | 周末去哪儿玩呢? | 3 | 1 |
| 2 | 104 | 推荐一家很棒的餐厅 | 1 | 2 |
| 3 | 107 | 今天的日落真美 | 3 | 1 |
| 3 | 105 | 打卡新开的咖啡店 | 2 | 2 |
+----------+------------+------------------------+----------+-----+
3. 筛选每个用户排名前2的朋友圈
执行SQL
select user_id,
moment_id,
content,
like_cnt,
rn as rank_num
from (
select m.user_id,
m.moment_id,
m.content,
t.like_cnt,
row_number() over (partition by m.user_id order by t.like_cnt desc) as rn
from t8_moments m
left join (
select moment_id,
count(distinct like_user_id) as like_cnt
from t8_likes
group by moment_id
) t on m.moment_id = t.moment_id
) tmp
where rn <= 2
order by user_id, rn
执行结果
+----------+------------+------------------------+----------+----------+
| user_id | moment_id | content | like_cnt | rank_num |
+----------+------------+------------------------+----------+----------+
| 1 | 101 | 今天天气真好! | 4 | 1 |
| 1 | 102 | 分享一首好听的歌 | 2 | 2 |
| 2 | 103 | 周末去哪儿玩呢? | 3 | 1 |
| 2 | 104 | 推荐一家很棒的餐厅 | 1 | 2 |
| 3 | 107 | 今天的日落真美 | 3 | 1 |
| 3 | 105 | 打卡新开的咖啡店 | 2 | 2 |
+----------+------------+------------------------+----------+----------+
五、常见坑点
坑1:LEFT JOIN vs INNER JOIN 对无点赞朋友圈的影响
如果某条朋友圈还没有人点赞,用 INNER JOIN 会让它直接消失。应该用 LEFT JOIN 保留所有朋友圈,点赞数用 COALESCE(like_cnt, 0) 填充为0。虽然排名可能靠后,但数据完整性不能丢。
坑2:COUNT DISTINCT 的必要性
同一个用户可以多次点赞同一条朋友圈(取消再点),如果不加 DISTINCT 会重复计算。COUNT(DISTINCT like_user_id) 确保每个用户只算一次。
坑3:ROW_NUMBER vs RANK 选哪个
如果两条朋友圈点赞数相同,ROW_NUMBER() 会随机选一条排前面,RANK() 和 DENSE_RANK() 会并列。产品需求是"取前2条",用 ROW_NUMBER 更合适——点赞数相同时取任意2条即可。
六、举一反三
- 按时间窗口统计:WHERE 条件限制
post_time范围,实现"本周最火朋友圈Top N" - 点赞+评论综合分:关联评论表,加权计算
total_score = like_cnt * 0.4 + comment_cnt * 0.6 - 好友维度的点赞排名:限定点赞用户必须是被统计用户的好友(关联好友关系表),只看"熟人圈"的热度
- 点赞速度分析:计算每条朋友圈达成Top 2点赞数所花的时间,识别"秒赞"异常行为
七、知识点总结
| 考点 | 说明 |
|---|---|
| LEFT JOIN + COUNT DISTINCT | 保留无点赞的朋友圈,去重统计真实点赞数 |
| ROW_NUMBER() OVER(PARTITION BY) | 按用户分组、按点赞数降序排名 |
| WHERE rn <= N | 外层筛选每组前N条记录 |
| 子查询分层 | 先聚合点赞数→关联朋友圈→排名→筛选,逐层处理 |
八、建表语句和数据插入
点击展开 DDL & DML
CREATE TABLE t8_moments (
moment_id bigint COMMENT '朋友圈ID',
user_id bigint COMMENT '用户ID',
content string COMMENT '朋友圈内容',
post_time string COMMENT '发布时间'
) COMMENT '朋友圈表';
-- 建表语句:点赞表
CREATE TABLE t8_likes (
moment_id bigint COMMENT '朋友圈ID',
like_user_id bigint COMMENT '点赞用户ID',
like_time string COMMENT '点赞时间'
) COMMENT '点赞表';
-- 数据插入:朋友圈表
INSERT INTO t8_moments VALUES
(101, 1, '今天天气真好!', '2023-03-01 10:00:00'),
(102, 1, '分享一首好听的歌', '2023-03-01 12:00:00'),
(103, 2, '周末去哪儿玩呢?', '2023-03-01 14:00:00'),
(104, 2, '推荐一家很棒的餐厅', '2023-03-02 09:00:00'),
(105, 3, '打卡新开的咖啡店', '2023-03-02 10:00:00'),
(106, 1, '晚上加班中...', '2023-03-02 20:00:00'),
(107, 3, '今天的日落真美', '2023-03-03 18:00:00');
-- 数据插入:点赞表
INSERT INTO t8_likes VALUES
(101, 2, '2023-03-01 10:05:00'),
(101, 3, '2023-03-01 10:10:00'),
(101, 4, '2023-03-01 10:15:00'),
(101, 5, '2023-03-01 11:00:00'),
(102, 2, '2023-03-01 12:30:00'),
(102, 3, '2023-03-01 13:00:00'),
(103, 1, '2023-03-01 14:30:00'),
(103, 3, '2023-03-01 15:00:00'),
(103, 4, '2023-03-01 16:00:00'),
(104, 1, '2023-03-02 09:30:00'),
(105, 1, '2023-03-02 10:30:00'),
(105, 2, '2023-03-02 11:00:00'),
(106, 2, '2023-03-02 20:30:00'),
(107, 1, '2023-03-03 18:30:00'),
(107, 2, '2023-03-03 19:00:00'),
(107, 4, '2023-03-03 19:30:00');
「数据仓库技术」文章同步更新,不错过每一篇干货

备注「数据仓库技术」加入社群,每日一道大厂SQL真题
