【2022.08.26 更新】
针对许多人的问题更新了代码~
SELECT
video_id,
ROUND((100 * finished_rate +
5 * like_cnt +
3 * comment_cnt +
2 * retweet_cnt) / (no_play_record_day_cnt + 1), 0) hot_index # 仔细查看指标定义,尤其是【新鲜度】
FROM (
SELECT
i.video_id,
# 播放率:计算的是每个video_id在近一个月的播放率平均值。
AVG(TIMESTAMPDIFF(second, start_time, end_time) >= duration) finished_rate,
SUM(if_like) like_cnt,
COUNT(comment_id) comment_cnt, # COUNT会自动过滤空值。
SUM(if_retweet) retweet_cnt,
# 没有播放日的计算:从当天开始,到该视频的最后一个日期。
# 【当天】:所有播放日期中的最大日期
#【视频的最后播放日期】:按video_id聚合的维度下的最大日期,注意题目要求以【end-time】为准。
DATEDIFF(DATE((SELECT MAX(end_time) FROM tb_user_video_log)),
MAX(DATE(end_time))) no_play_record_day_cnt # 注意这里先要取出日期,再取最大值。
FROM tb_video_info i
JOIN tb_user_video_log USING(video_id)
# 【近一个月内发布】的日期筛选
#【近】:表示从当天开始,即所有播放日期中的最大日期
# 【一个月内】:表示从当天开始,前推29天 --- 日期前推是【n-1】
WHERE DATEDIFF(DATE((SELECT MAX(end_time) FROM tb_user_video_log)), DATE(release_time)) <= 29
GROUP BY 1) t
ORDER BY 2 DESC
LIMIT 3
【旧帖】
时间: 37ms 内存:6408KB
两个坑。
一、关于时间窗口的筛选
需求是最后播放日期往前推30天,如果用前面几题见到过的DATEDIFF法:
后面那个不可以用end_time,而是应该用release_time, 因为存在视频发布当天并没有播放记录的情况。
举个例子:10.03往前推30天是09.04。我们要获取的统计时间区间是09.04-10.03。假设某个视频09.01发布,但是5天后才有第一次播放记录,那么这个视频最早的end_time是09.06,按照这个end_time,用DATEDIFF法来生成,得到的时间区间是09.06-10.03,明显不完整。个人感觉题目也是没有完全讲清楚。。
——————————————————————————————————
二、要过滤掉没有播放记录的视频
因为存在list里有,但log完全没有播放记录的video,比如2004。。所以在最初的子查询里面:
如果用LEFT JOIN,后面的WHERE要加上end_time IS NOT NULL
或者
直接用内连接JOIN过滤
——————————————————————————————————
代码如下:
SELECT
video_id,
ROUND((100 * finished_rate
+ 5 * like_cnt
+ 3 * comment_count
+ 2 * retweet_cnt) / (unfinished_day_cnt + 1)) hot_index
FROM (
SELECT
i.video_id,
SUM(TIMESTAMPDIFF(second, start_time, end_time) >= duration) / COUNT(*) finished_rate,
SUM(if_like = 1) like_cnt,
SUM(IF(comment_id IS NOT NULL, 1, 0)) comment_count,
SUM(if_retweet = 1) retweet_cnt,
DATEDIFF(DATE((SELECT MAX(end_time) FROM tb_user_video_log)), MAX(DATE(end_time))) unfinished_day_cnt
FROM tb_video_info i
JOIN tb_user_video_log USING(video_id)
WHERE DATEDIFF(DATE((SELECT MAX(end_time) FROM tb_user_video_log)), DATE(release_time)) <= 29
GROUP BY 1
) t
ORDER BY 2 DESC LIMIT 3