做题笔记:SQL Sever 方式做牛客SQL的题目--SQL156

----SQL156 各个视频的平均完播率

问题:计算2021年里有播放记录的每个视频的完播率(结果保留三位小数),并按完播率降序排序

注:视频完播率是指完成播放次数占总播放次数的比例。

简单起见,结束观看时间与开始播放时间的差>=视频时长时,视为完成播放。

输出顺序:video_id | avg_comp_play_rate

表的创建及数据的插入:

sql 复制代码
DROP TABLE IF EXISTS tb_user_video_log, tb_video_info;
CREATE TABLE tb_user_video_log
(
    id         INT PRIMARY KEY identity,-- '自增ID',
    uid        INT NOT NULL,-- '用户ID',
    video_id   INT NOT NULL,-- '视频ID',
    start_time datetime,-- '开始观看时间',
    end_time   datetime,-- '结束观看时间',
    if_follow  TINYINT,-- '是否关注',
    if_like    TINYINT,-- '是否点赞',
    if_retweet TINYINT,-- '是否转发',
    comment_id INT,--'评论ID'
);

CREATE TABLE tb_video_info
(
    id           INT PRIMARY KEY identity,-- '自增ID',
    video_id     INT UNIQUE  NOT NULL,-- '视频ID',
    author       INT         NOT NULL,-- '创作者ID',
    tag          VARCHAR(16) NOT NULL,-- '类别标签',
    duration     INT         NOT NULL,-- '视频时长(秒数)',
    release_time datetime    NOT NULL,-- '发布时间'
);

INSERT INTO tb_user_video_log(uid, video_id, start_time, end_time, if_follow, if_like, if_retweet, comment_id)
VALUES (101, 2001, '2021-10-01 10:00:00', '2021-10-01 10:00:30', 0, 1, 1, null),
       (102, 2001, '2021-10-01 10:00:00', '2021-10-01 10:00:24', 0, 0, 1, null),
       (103, 2001, '2021-10-01 11:00:00', '2021-10-01 11:00:34', 0, 1, 0, 1732526),
       (101, 2002, '2021-09-01 10:00:00', '2021-09-01 10:00:42', 1, 0, 1, null),
       (102, 2002, '2021-10-01 11:00:00', '2021-10-01 11:00:30', 1, 0, 1, null),
		
		(103, 2002, '2021-10-01 10:59:05', '2021-10-01 11:00:05', 1, 0, 1, null),
		(101, 2003, '2020-09-01 10:00:00', '2020-09-01 10:01:42', 1, 0, 1, null),
		(102, 2003, '2021-09-01 10:00:00', '2021-09-01 10:00:42', 1, 0, 1, null);

INSERT INTO tb_video_info(video_id, author, tag, duration, release_time)
VALUES (2001, 901, '影视', 30, '2021-01-01 7:00:00'),
       (2002, 901, '美食', 60, '2021-01-01 7:00:00'),
       (2003, 902, '旅游', 90, '2021-01-01 7:00:00');

解题思路:

① 所查信息涉及两表,所以需要多表查询 - join

② 视频每次播放的实际时间 = 结束时间 - 开始时间

sql 复制代码
datediff(second,start_time,end_time)		--时间差,以秒为单位

③ 以视频分组,比较实际播放时间>= 视频时长(秒数) 的并统计个数 / 视频播放总次数

④ 筛选2021年的数据

查询如下:

sql 复制代码
 select video_id,
		Convert(decimal(18,3),count(iif(watch_time >= duration,1,null))* 1.0 / count(video_id)) avg_comp_play_rate
 from (
		 select tu.video_id,year(start_time) as year_v,datediff(second,start_time,end_time)  as watch_time,tv.duration
		 from tb_user_video_log tu
		 join tb_video_info tv
		 on tu.video_id = tv.video_id
		)t
 where year_v = '2021'
 group by video_id

上述查询用了一层嵌套,有利于在写查询时候理清思路,可以优化简洁代码如下:

sql 复制代码
 select tu.video_id,
		Convert(decimal(18,3),count(iif(datediff(second,start_time,end_time) >= duration,1,null))* 1.0 / count(tu.video_id)) avg_comp_play_rate
 from tb_user_video_log tu
 join tb_video_info tv
 on tu.video_id = tv.video_id
 where year(start_time) = '2021'
 group by tu.video_id

做题总结:

① 需要注意count(iif(watch_time >= duration,1,null))的使用,在开始null处写的0是错误的,count统计返回的元素个数1或0都会被统计,所以导致最后完播率都是100%,如果返回是null则不会被count统计,可筛选出符合要求的数据。如果想反回0,可以用sum函数替换count函数:sum(iif(watch_time >= duration,1,0))

DATEDIFF 函数
DATEDIFF函数用于计算两个日期之间的差异,可以以天、小时、分钟、秒等不同的单位来返回结果。
DATEDIFF的基本语法如下:

sql 复制代码
DATEDIFF(datepart, startdate, enddate)

在次语法中:

datepart 表示需要计算的时间单位,可以是以下值之一:

"year"(年);"quarter"(季度);"month"(月)

"day"(天);"hour"(小时);"minute"(分钟)

"second"(秒)

startdate 表示起始日期;enddate 表示结束日期。

Convert 函数

sql 复制代码
Convert(decimal(18,3), x * 1.0 / y)

Convert 函数将x/y的结果转化为decimal(18,3)数据类型:decimal(18,3)是一种数据类型,用于存储具有总共18位数值的数字,其中包括3位小数,即保留三位小数

相关推荐
tatasix34 分钟前
MySQL UPDATE语句执行链路解析
数据库·mysql
dr李四维41 分钟前
iOS构建版本以及Hbuilder打iOS的ipa包全流程
前端·笔记·ios·产品运营·产品经理·xcode
南城花随雪。1 小时前
硬盘(HDD)与固态硬盘(SSD)详细解读
数据库
儿时可乖了1 小时前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
懒是一种态度1 小时前
Golang 调用 mongodb 的函数
数据库·mongodb·golang
天海华兮1 小时前
mysql 去重 补全 取出重复 变量 函数 和存储过程
数据库·mysql
gma9992 小时前
Etcd 框架
数据库·etcd
爱吃青椒不爱吃西红柿‍️2 小时前
华为ASP与CSP是什么?
服务器·前端·数据库
Yz98762 小时前
hive的存储格式
大数据·数据库·数据仓库·hive·hadoop·数据库开发
武子康2 小时前
大数据-230 离线数仓 - ODS层的构建 Hive处理 UDF 与 SerDe 处理 与 当前总结
java·大数据·数据仓库·hive·hadoop·sql·hdfs