题解 | #未完成率较高的50%用户近三个月答卷情况#

未完成率较高的50%用户近三个月答卷情况

http://www.nowcoder.com/practice/3e598a2dcd854db8b1a3c48e5904fe1c


一、知识点总结

把有用知识点写在前面,以方便自个儿收藏观看😊。
1)5个常用的排序函数
  • rank() over() 1 2 2 4 4 6  (计数排名,跳过相同的几个,eg.没有3没有5)\
  • row_number() over() 1 2 3 4 5 6 (赋予唯一排名)
  • dense_rank() over() 1 2 2 3 3 4 (不跳过排名,可以理解为对类别进行计数)
  • percent_rank() over() 按照数字所在的位置进行百分位分段
  • ntile(n)over() 将数字按照大小平均分成n段
  • lead(字段名,n)over()把字段数据向前移n个单元格
  • lag(字段名,n)over()把字段数据向后移n个单元格
案例:
select * ,
    row_number()over(order by uid) row_number1, /*按照uid的大小不重不漏1 2 3 4 5 6 7 */
    rank()over(order by uid) rank1, /*按照uid的大小并列第一无第二,1 1 1 4 5 5 7*/
    dense_rank()over(order by uid) dense_rank1,/*按照uid的大小并列第一有第二,1 1 1  2 3 3 4*/
    percent_rank()over(order by uid) percent_rank1,/*按照uid的大小进行百分法排序*/
    ntile(2)over(order by uid) ntile1,/*按照uid的大小,把uid评价分成2组*/
    lead(uid)over(order by uid) lead1,/*把uid向上推1个位置*/
    lag(uid)over(order by uid) lag1 /*把uid向下推1个位置*/    
from user_id;


二、题目解读与解题步骤拆分

1、题目解读
  • 求:请统计SQL试卷上未完成率较高的50%用户中,6级和7级用户在有试卷作答记录的近三个月中,每个月的答卷数目和完成数目。按用户ID、月份升序排序。
  • 题目中的坑:未完成率较高的50%用户,即为完成率低于50%的用户。
  • 需求字段:uid 、 start_month、 total_cnt    complete_cnt

2、步骤拆分
1)SQL试卷上未完成率较高的50%用户。
  • 完成率=用户完成的题/用户答题数:COUNT(submit_time) / COUNT(start_time)
  • 对完成率进行排序:PERCENT_RANK()OVER()
  • SQL试卷

2)6级和7级用户在有试卷作答记录的近三个月中。
  • 查找6,7级用户的uid
  • 对作答记录进行排序取近3个月

3)每个月的答卷数目和完成数目。
4)按用户ID、月份升序排序。

三、步骤代码

1)SQL完成率=用户完成的题/用户答题数
  • 用户完成题数:COUNT(submit_time) 
  • 用户答题数:COUNT(start_time) 
  • 完成率=COUNT(submit_time) / COUNT(start_time)
  • SELECT exam_id FROM examination_info WHERE tag='SQL'

2)对完成率进行排序,以及完成率排名后50%的用户
  • PERCENT_RANK()OVER( ORDER BY count(submit_time)/count(start_time) ) rate_rk
  • rate_rk<=50%
SELECT uid,COUNT(submit_time)/COUNT(start_time) rk_com
		,PERCENT_RANK()over( ORDER BY COUNT(submit_time)/COUNT(start_time) ) rate_rk
		FROM exam_record
		WHERE  exam_id IN 
		(SELECT exam_id FROM examination_info WHERE tag='SQL')
GROUP BY uid
/*对SQL用户的完成率进行排序*/

3)查找6,7级用户的uid
  • SELECT uid FROM user_info WHERE level IN (6,7);
SELECT * 
	FROM (
		SELECT uid
		,PERCENT_RANK()over( ORDER BY count(submit_time)/count(start_time) ) rate_rk
		FROM exam_record
		WHERE  exam_id IN 
		(SELECT exam_id FROM examination_info WHERE tag='SQL')
		GROUP BY uid
		) A -- 对用户完成率进行排序
	WHERE rate_rk<=0.5 -- 查找完成率排名低的50%用户
	AND uid IN (SELECT uid FROM user_info WHERE level IN (6,7))-- 查找6,7级用户

以上找出来满足题设需求的用户”SQL试卷上未完成率较高的50%用户中,6级和7级用户“只有1002

4)对作答记录时间进行排序取近3个月
SELECT * ,dense_rank()over(partition by uid order by date_format(start_time,'%Y-%m') desc) time_rk -- 对作答时间进行排序
FROM exam_record


5)每个用户每个月的答卷数目和完成数目,并按用户ID、月份升序排序。
SELECT t1.uid,
    DATE_FORMAT(start_time,'%Y%m')start_month,  -- 取月份数
    COUNT(start_time) total_cnt, -- 答卷数
    COUNT(submit_time) complete_cnt  -- 完成数
FROM (
	SELECT * ,
    dense_rank()over(partition by uid order by date_format(start_time,'%Y-%m') desc) time_rk -- 对作答时间进行排序
	FROM exam_record
	)t1    
WHERE time_rk<=3 -- 查找作答时间最近的3个月
GROUP BY uid,start_month 
ORDER BY uid,start_month -- 按照用户id和月份进行升序排序
;

四、完整代码组装

SELECT t1.uid,
    DATE_FORMAT(start_time,'%Y%m')start_month,  -- 取月份数
    COUNT(start_time) total_cnt, -- 答卷数
    COUNT(submit_time) complete_cnt  -- 完成数
FROM (
    SELECT * ,
    dense_rank()over(partition by uid order by date_format(start_time,'%Y-%m') desc) time_rk -- 对作答时间进行排序
    FROM exam_record
    )t1
    
RIGHT JOIN (
    SELECT * 
    FROM (
        SELECT uid,
        PERCENT_RANK()over( ORDER BY count(submit_time)/count(start_time) ) rate_rk -- 对完成率进行分数排序
        FROM exam_record
        WHERE  exam_id IN 
        (SELECT exam_id FROM examination_info WHERE tag='SQL') -- SQL试卷
        GROUP BY uid
        ) A
    WHERE rate_rk<=0.5  -- 查找排名低于50%的用户
    AND uid IN (SELECT uid FROM user_info WHERE level IN (6,7)) -- 查找6.7级用户
    )t2 ON t1.uid=t2.uid
    
WHERE time_rk<=3 -- 查找作答时间最近的3个月
GROUP BY uid,start_month 
ORDER BY uid,start_month -- 按照用户id和月份进行升序排序
;

SQL解题集 文章被收录于专栏

这是牛客SQL相关的解题集

全部评论
我每一个小步骤都能写出来,但是一旦尝试组装起来就感觉太乱了,完全不知道怎么组装了。。。T.T
7 回复 分享
发布于 2022-07-29 19:13
想问下,为什么是right join,用inner jion 或jion 不行吗?
2 回复 分享
发布于 2023-02-20 09:26 北京
说实话老感觉那个percent_rank理解起来怪怪的
2 回复 分享
发布于 2022-05-19 16:59
请问为什么不能连接3表,把level是6或7级和tag=SQL用and连接写在一起呢?
1 回复 分享
发布于 2023-02-27 18:26 英国
你好想问一下为什么查找完成率低于50%的用户不能在GOUP BY 后面用HAVING
1 回复 分享
发布于 2023-02-01 09:26 广东
较高的50%用户,又不是高于50%的用户,为啥那么多题目都怪怪的
1 回复 分享
发布于 2023-01-01 20:15 山东
这个答题时间不对,1001取3的时候时间是2月
1 回复 分享
发布于 2022-08-04 10:06
想问下如果完成率是50%,未完成率也是50%,那要是按未完成率高于50%这个用户是符合要求的,要是按完成率<50%会把这个用户过滤掉,这个有点想不通
1 回复 分享
发布于 2022-06-23 20:10
我觉得你的思路比别人的都清晰,他们的好乱
1 回复 分享
发布于 2022-04-15 11:35
牛,学习到了,谢谢
点赞 回复 分享
发布于 2023-07-12 01:29 上海
这个会有多余的数据吧 如果存在一个6/7级且未完成率为较高的50%的用户,但是他只有两个月答题了,没有三个月的答题数据,这样就不符合题目要求的三个月答卷情况,但是通过WHERE time_rk<=3 无法剔除掉这个用户
点赞 回复 分享
发布于 2022-09-12 14:52 湖南
请问为什么percent_rank函数 over后面加上partition by uid会报错呢 不理解呀 一般排序函数大多over后面我都加上partition by 这里不理解为什么不能加partition by uid
点赞 回复 分享
发布于 2022-07-11 23:35
请问为什么percent_rank函数 over后面加上partition by uid会报错呢 不理解呀 一般排序函数大多over后面我都加上partition by 这里不理解为什么不能加partition by uid
点赞 回复 分享
发布于 2022-07-11 23:35
分不清啥时候窗口函数over后面不加partition :(
点赞 回复 分享
发布于 2022-07-04 04:06

相关推荐

评论
131
24
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务