SQL 热门话题Top10及参与用户数:GROUP BY + LIMIT(快手面试题)
一、题目
已知有表 t7_topic_video 记录了视频与话题的关联关系(一个视频可以带多个话题标签,因此同一个 video_id 可能对应多行,每行是该视频与某个话题的关联),包含字段:video_id(视频ID)、topic_id(话题ID)、topic_name(话题名称)、author_id(作者ID)、create_time(视频创建时间)。
请统计参与视频数量最多的 Top 10 话题,输出话题ID、话题名称、参与视频数、参与作者数(去重),按参与视频数降序排列。如果视频数相同,按话题ID升序排列。
样例数据
+-----------+-----------+-------------+------------+----------------------+
| video_id | topic_id | topic_name | author_id | create_time |
+-----------+-----------+-------------+------------+----------------------+
| V001 | T001 | #挑战30天 | a001 | 2024-06-01 08:00:00 |
| V001 | T002 | #夏日穿搭 | a001 | 2024-06-01 08:00:00 |
| V002 | T001 | #挑战30天 | a002 | 2024-06-01 09:00:00 |
| V003 | T001 | #挑战30天 | a001 | 2024-06-01 10:00:00 |
| V004 | T001 | #挑战30天 | a003 | 2024-06-01 11:00:00 |
| V004 | T002 | #夏日穿搭 | a003 | 2024-06-01 11:00:00 |
| V004 | T003 | #美食探店 | a003 | 2024-06-01 11:00:00 |
| V005 | T002 | #夏日穿搭 | a002 | 2024-06-01 12:00:00 |
| V006 | T002 | #夏日穿搭 | a004 | 2024-06-01 13:00:00 |
| V007 | T003 | #美食探店 | a004 | 2024-06-01 14:00:00 |
| V008 | T003 | #美食探店 | a005 | 2024-06-01 15:00:00 |
| V009 | T004 | #萌宠日常 | a001 | 2024-06-01 16:00:00 |
| V010 | T005 | #健身打卡 | a006 | 2024-06-01 17:00:00 |
+-----------+-----------+-------------+------------+----------------------+
V001 带了 T001、T002 两个话题,V004 带了 T001、T002、T003 三个话题,因此它们在表中各占多行。
二、思路分析
本题是对 GROUP BY + COUNT DISTINCT 的经典考察。关键在于理解表的粒度:
-
表粒度是「视频-话题」关联:一个视频带 N 个话题就有 N 行。所以
count(video_id)统计的实际上是该话题下「视频-话题」关联的数量,由于每个 (video, topic) 对唯一,这个值正好等于「参与该话题的视频数」。多话题视频(如 V001)会同时计入它参与的每个话题,这是符合业务语义的。 -
作者数要去重:
count(distinct author_id)统计参与作者数,因为同一个作者可能为同一话题发布多个视频(如 a001 发布了 V001、V003 都带 #挑战30天)。 -
排序取 Top 10:
order by video_cnt desc, topic_id asc+limit 10。
| 维度 | 评分 |
|---|---|
| 题目难度 | ⭐️ |
| 题目清晰度 | ⭐️⭐️⭐️⭐️⭐️ |
| 业务常见度 | ⭐️⭐️⭐️⭐️⭐️ |
三、逐步推导
1.按话题统计视频数和参与作者数
按 topic_id 分组,count(video_id) 统计参与视频数,count(distinct author_id) 统计去重作者数。
执行SQL
select
topic_id,
topic_name,
count(video_id) as video_cnt,
count(distinct author_id) as author_cnt
from t7_topic_video
group by topic_id, topic_name
order by video_cnt desc, topic_id asc
执行结果
+-----------+-------------+------------+-------------+
| topic_id | topic_name | video_cnt | author_cnt |
+-----------+-------------+------------+-------------+
| T001 | #挑战30天 | 4 | 3 |
| T002 | #夏日穿搭 | 4 | 4 |
| T003 | #美食探店 | 3 | 3 |
| T004 | #萌宠日常 | 1 | 1 |
| T005 | #健身打卡 | 1 | 1 |
+-----------+-------------+------------+-------------+
5 rows selected (0.674 seconds)(https://www.dwsql.com)
V001、V004 是多话题视频:V001 同时计入 T001 和 T002,V004 同时计入 T001、T002、T003。
2.取 Top 10 热门话题
添加 limit 10 限制,得到最终结果。
执行SQL
select
topic_id,
topic_name,
count(video_id) as video_cnt,
count(distinct author_id) as author_cnt
from t7_topic_video
group by topic_id, topic_name
order by video_cnt desc, topic_id asc
limit 10
执行结果
+-----------+-------------+------------+-------------+
| topic_id | topic_name | video_cnt | author_cnt |
+-----------+-------------+------------+-------------+
| T001 | #挑战30天 | 4 | 3 |
| T002 | #夏日穿搭 | 4 | 4 |
| T003 | #美食探店 | 3 | 3 |
| T004 | #萌宠日常 | 1 | 1 |
| T005 | #健身打卡 | 1 | 1 |
+-----------+-------------+------------+-------------+
5 rows selected (0.371 seconds)(https://www.dwsql.com)
#挑战30天 和 #夏日穿搭 视频数并列第一(均为4个),按 topic_id 升序,#挑战30天(T001) 排在 #夏日穿搭(T002) 前。
四、常见坑点
坑1:作者数必须去重
同一作者可为同一话题发布多个视频(如 a001 的 V001、V003 都带 #挑战30天),count(author_id) 会重复计数。必须用 count(distinct author_id),否则 a001 被算成 2 个作者。
坑2:并列话题的排序规则
视频数相同时需明确次级排序键。题目要求 video_cnt desc, topic_id asc,若漏掉 topic_id asc,并列话题的顺序不稳定,Top10 结果可能漂移。
坑3:多话题视频会同时计入多个话题
V001 带两个话题,在统计时同时计入 T001 和 T002。这是业务上正确的——一个视频确实"参与"了多个话题。但如果后续要做「全网去重视频总数」这类跨话题汇总,就不能简单把各话题 video_cnt 相加,否则多话题视频会被重复统计。
五、知识点总结
| 考点 | 说明 |
|---|---|
| count(video_id) 视频数 | 表粒度是视频-话题关联,每个话题下的行数即参与视频数 |
| count(distinct author_id) | 同一作者多视频参与同一话题,作者数须去重 |
| order by 多列排序 | video_cnt desc, topic_id asc 指定并列时的次级排序键 |
| group by + limit | 分组聚合后配合 order by + limit 取 Top N |
六、建表语句和数据插入
点击展开 DDL & DML
--建表语句
create table if not exists t7_topic_video (
video_id string comment '视频ID',
topic_id string comment '话题ID',
topic_name string comment '话题名称',
author_id string comment '作者ID',
create_time string comment '视频创建时间'
);
--数据插入
insert into t7_topic_video(video_id, topic_id, topic_name, author_id, create_time) values
('V001', 'T001', '#挑战30天', 'a001', '2024-06-01 08:00:00'),
('V001', 'T002', '#夏日穿搭', 'a001', '2024-06-01 08:00:00'),
('V002', 'T001', '#挑战30天', 'a002', '2024-06-01 09:00:00'),
('V003', 'T001', '#挑战30天', 'a001', '2024-06-01 10:00:00'),
('V004', 'T001', '#挑战30天', 'a003', '2024-06-01 11:00:00'),
('V004', 'T002', '#夏日穿搭', 'a003', '2024-06-01 11:00:00'),
('V004', 'T003', '#美食探店', 'a003', '2024-06-01 11:00:00'),
('V005', 'T002', '#夏日穿搭', 'a002', '2024-06-01 12:00:00'),
('V006', 'T002', '#夏日穿搭', 'a004', '2024-06-01 13:00:00'),
('V007', 'T003', '#美食探店', 'a004', '2024-06-01 14:00:00'),
('V008', 'T003', '#美食探店', 'a005', '2024-06-01 15:00:00'),
('V009', 'T004', '#萌宠日常', 'a001', '2024-06-01 16:00:00'),
('V010', 'T005', '#健身打卡', 'a006', '2024-06-01 17:00:00');
「数据仓库技术」文章同步更新,不错过每一篇干货

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