题解 | 平均播放进度大于60%的视频类别
平均播放进度大于60%的视频类别
https://www.nowcoder.com/practice/c60242566ad94bc29959de0cdc6d95ef
一、题目思路
题目要求按 tag 统计视频的平均播放进度,并满足两点:
- 无播放记录的标签不输出
- 当播放时长大于视频时长时,播放进度按 100% 计算
因此解题步骤很清晰:
- 用
video_id连接视频信息表和播放日志表 - 用
TIMESTAMPDIFF计算每条记录的播放时长 - 用
LEAST将单条记录播放进度封顶为100% - 按
tag分组求平均播放进度 - 用
HAVING筛选平均进度大于 60% 的标签 - 用
CONCAT拼接百分号输出结果
二、参考 SQL
SELECT v.tag,
CONCAT(
ROUND(
AVG(
LEAST(TIMESTAMPDIFF(SECOND, u.start_time, u.end_time) / v.duration, 1)
) * 100,
2
),
'%'
) AS avg_play_progress
FROM tb_video_info v
JOIN tb_user_video_log u
ON v.video_id = u.video_id
GROUP BY v.tag
HAVING AVG(
LEAST(TIMESTAMPDIFF(SECOND, u.start_time, u.end_time) / v.duration, 1)
) * 100 > 60
ORDER BY AVG(
LEAST(TIMESTAMPDIFF(SECOND, u.start_time, u.end_time) / v.duration, 1)
) * 100 DESC;
三、知识点整理
1. WHERE 和 HAVING 的辨析
区别
WHERE:分组前筛选行HAVING:分组后筛选组
本题中的用法
本题要筛选的是:
AVG(...) * 100 > 60
这是对分组后的平均值进行筛选,属于聚合结果,因此必须用 HAVING,不能用 WHERE。
通用模板
SELECT 分组字段, 聚合函数(...) FROM 表 WHERE 行条件 GROUP BY 分组字段 HAVING 聚合条件
记忆
- 筛单行:
WHERE - 筛平均值、总和、计数等聚合结果:
HAVING
2. CONCAT 函数
作用
用于拼接字符串。
本题中的作用
把数值型平均播放进度拼接成带 % 的结果。
通用模板
CONCAT(字符串1, 字符串2, ...)
本题常见写法:
CONCAT(ROUND(某比例 * 100, 2), '%')
3. TIMESTAMPDIFF 函数
作用
计算两个时间之间的差值。
基本格式
TIMESTAMPDIFF(单位, 开始时间, 结束时间)
本题中的作用
计算每条播放记录的播放时长:
TIMESTAMPDIFF(SECOND, u.start_time, u.end_time)
表示播放秒数。
通用模板
TIMESTAMPDIFF(SECOND, start_col, end_col)
常用于停留时长、播放时长、处理耗时等题目。
4. LEFT JOIN 和 JOIN 的辨析
JOIN(INNER JOIN)
只保留两表中能匹配上的记录。
LEFT JOIN
保留左表全部记录,右表匹配不到时补 NULL。
本题为什么用 JOIN
题目要求没有播放记录的 tag 不输出,因此只保留有匹配播放日志的数据即可,用 JOIN 更合适。
通用模板
FROM A JOIN B ON A.id = B.id
FROM A LEFT JOIN B ON A.id = B.id
选择原则
- 只统计有匹配数据的记录:
JOIN - 需要保留左表全部记录:
LEFT JOIN
5. LEAST 函数
作用
返回多个值中的最小值。
本题中的作用
将单条播放进度封顶为 1,也就是 100%:
LEAST(TIMESTAMPDIFF(SECOND, u.start_time, u.end_time) / v.duration, 1)
如果播放比例超过 1,就按 1 计算。
通用模板
LEAST(表达式, 上限值)
在“比例最多按 100% 算”的题目中很常见:
LEAST(实际值 / 总值, 1)
四、本题总结
这题本质上是一个连接 + 分组聚合 + 百分比格式化的问题:
- 用
JOIN去掉无播放记录的标签 - 用
TIMESTAMPDIFF算播放时长 - 用
LEAST控制播放进度不超过 100% - 用
AVG求每个tag的平均播放进度 - 用
HAVING筛选平均进度大于 60% - 用
CONCAT输出百分比格式
五、通用模板
SELECT 分组字段,
CONCAT(ROUND(AVG(LEAST(实际值 / 总值, 1)) * 100, 2), '%') AS 结果
FROM 主表 A
JOIN 明细表 B
ON 连接条件
WHERE 行级条件
GROUP BY 分组字段
HAVING 聚合条件
ORDER BY AVG(LEAST(实际值 / 总值, 1)) DESC;
这类模板可以直接迁移到:
- 播放进度
- 完成率
- 达成率
- 使用率
- 学习进度

查看5道真题和解析