跳到主要内容

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 10order 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真题

交流微信二维码

你可能还想看