题解 | #每月及截止当月的答题情况#

每月及截止当月的答题情况

http://www.nowcoder.com/practice/1ce93d5cec5c4243930fc5e8efaaca1e

一、考总结拓展&完整代码

 题设的考点通篇围绕这几个聚合窗口函数以及结合GROUP BY函数的使用。

1) 聚合窗口函数
  • MIN()OVER() :不改变表结构的前提下,计算出最小值
  • MAX()OVER():不改变表结构的前提下,计算出最大值
  • COUNT()OVER():不改变表结构的前提下,计数
  • SUM()OVER():不改变表结构的前提下,求和
  • AVG()OVER():不改变表结构的前提下,求平均值
2)排序窗口函数
  • percent_rank() over() 按照数字所在的位置进行百分位分段
  • ntile(n)over() 将数字按照大小平均分成n段
  • lead(字段名,n)over()把字段数据向前移n个单元格
  • lag(字段名,n)over()把字段数据向后移n个单元格
3)完整代码
SELECT start_month ,#每个月     COUNT(DISTINCT uid) mau, #月活用户数   
    SUM(new_day) month_add_uv, #新增用户
    MAX(SUM(new_day))OVER(ORDER BY start_month) max_month_add_uv, #截止当月的单月最大新增用户数
    SUM(SUM(new_day))OVER(ORDER BY start_month) cum_sum_uv
FROM (
    SELECT *,DATE_FORMAT(start_time,'%Y%m') start_month,     IF(start_time=MIN(start_time)OVER(PARTITION BY uid),1,0) new_day
    FROM exam_record)t1
GROUP BY start_month;

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

1、题目解读

求:请输出自从有用户作答记录以来,每月的试卷作答记录中月活用户数、新增用户数、截止当月的单月最大新增用户数、截止当月的累积用户数。结果按月份升序输出

题目中隐藏的坑&难点
  • 坑1:新增用户的定义——首次登录的用户,也就是把用户最早登录的那天定义为首次登录日期。
  • 坑2:截止当月的单月最大新增用户数:按照月份依次对比每个月的新增用户数的大小取大值用MAX()OVER(order by start_month)
  • 坑3:截止当月的累积用户数:按照月份依次累加新增用户数用SUM()OVER(ORDER BY  start_month)

需求字段:


  • start_month :月份
  • mau :月活用户数
  • month_add_uv :新增用户数
  • max_month_add_uv:截止当月的单月最大新增用户数
  • cum_sum_uv:截止当月的累积用户数


2、步骤拆分

思路比较简单,就是先处理新用户数据,再用窗口函数进行各种查询。
先基于原表,新增一列对新用户的定义列:定义新增用户“首次登录日取1,其他日期取0”,建立子表t1。再基于t1的基础上查询月活用户数,新增用户数,截止当月的单月最大新增用户数,截止当月的累积用户数。

三、步骤代码

1)定义新用户
  • 先查每一个用户的首次登录日期
MIN(start_time)OVER(PARTITION BY uid) AS new_user_day #第一天登录
  • 定义新用户
IF(start_time = new_user_day,1,0) AS new_day # 若用户的登录时间等于首次登录时间则定义为新用户,新用户被标记为1,其他标记为0。
IF(start_time=MIN(start_time)OVER(PARTITION BY uid),1,0) AS new_day #完整的表达
  • 新用户被定义出来后运行该代码可得下表
SELECT *,DATE_FORMAT(start_time,'%Y%m') start_month,
	IF(start_time=MIN(start_time)OVER(PARTITION BY uid),1,0) new_day
FROM exam_record
#子表命名为t1


2)统计月活用户
  • 月活用户需要去重COUNT(DISTICT uid) mau
3)统计月新增用户
  • 对每天的新增用户进行求和SUM(new_day) month_add_uv
SELECT start_month ,#每个月
	COUNT(DISTINCT uid) mau, #月活用户数   
    SUM(new_day) month_add_uv #新增用户
FROM (
    SELECT *,DATE_FORMAT(start_time,'%Y%m') start_month,
	IF(start_time=MIN(start_time)OVER(PARTITION BY uid),1,0) new_day
    FROM exam_record)t1
GROUP BY start_month
;

4)查找截止当月的单月最大新增用户数
  • 使用窗口函数按月依次查找最大每个月最大的新增用户数MAX(month_add_uv)OVER(order by start_month)
5)统计截止当月的累积用户数
  • 使用窗口函数按月累加新增用户数SUM(month_add_uv)OVER(order by start_month)
6)按月份升序输出&完整代码
SELECT start_month ,#每个月     COUNT(DISTINCT uid) mau, #月活用户数   
    SUM(new_day) month_add_uv, #新增用户
    MAX(SUM(new_day))OVER(ORDER BY start_month) max_month_add_uv, #截止当月的单月最大新增用户数
    SUM(SUM(new_day))OVER(ORDER BY start_month) cum_sum_uv
FROM (
    SELECT *,DATE_FORMAT(start_time,'%Y%m') start_month,     IF(start_time=MIN(start_time)OVER(PARTITION BY uid),1,0) new_day
    FROM exam_record)t1
GROUP BY start_month;

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

这是牛客SQL相关的解题集

全部评论
真的牛,这是我想不到的思路了
4 回复 分享
发布于 2023-03-08 17:13 新疆
又仔细看了一遍楼主的题解,看懂了,其实这道题最难的地方是求新增用户数。楼主思路:start_time = min(start_time) partition(partition by uid order by start_time), 找的是每个用户的首条访问记录 时间+日期 = 最小的时间+日期,即为该用户的首条访问记录 也就说明这个记录表示新来了个用户,而不是求该用户的首次访问日期。后边group by月份的时候,其实就是统计每个月内,有几条首次访问记录,就有几个新用户(一个用户只会有一条首次访问记录,所以有几条首次访问记录就代表新来了几个用户)。牛逼之处在于,我只要计算本月有几个首次访问记录 即新用户就行了,根本不用和上个月对比哪些是老用户哪些是老用户(老用户的访问记录或者叫非首次访问记录都被标记为0了)。
2 回复 分享
发布于 2023-01-20 01:05 山东
妙妙屋
1 回复 分享
发布于 2024-06-17 20:09 北京
我啥时候才能这么强
1 回复 分享
发布于 2024-05-24 16:33 台湾
楼主有个小疑问,用min(start_time)找到首次访问日期,但如果首次访问日期有多条答卷记录,下面sum(首次访问日期)会把一个人的多条访问记录统计为多个人,因为一个在首次访问日期有答卷记录 那么这些答卷首次访问日期的记录全部会被记为1的,所以一个用户在首次访问日期有多条答卷记录的情况下用sum统计怎么用户去重呢?
1 回复 分享
发布于 2023-01-19 23:55 山东
每月新增好像没有去重
1 回复 分享
发布于 2022-05-17 16:12
new_day用的厉害!
点赞 回复 分享
发布于 2024-02-22 16:15 香港
厉害,我还在想用group_concat做一个不重复的uid表来查
点赞 回复 分享
发布于 2024-01-12 12:30 北京
我想问一下什么时候聚合函数大写什么时候小写呢 我有时候小写就不对
点赞 回复 分享
发布于 2023-08-17 08:15 吉林
提交不通过,他这题新增用户指的是在以往未出现的用户。
点赞 回复 分享
发布于 2023-08-10 10:04 浙江
小姐姐真厉害,学习
点赞 回复 分享
发布于 2023-05-17 14:12 广西
代码片段: MAX(SUM(new_day)) over(order by start_month) max_month_add_uv,#截止当月的单月最大新增用户数 问题: 为什么是 MAX(SUM(new_day)) over(order by start_month) max_month_add_uv,而不是 MAX(new_day) over(order by start_month) max_month_add_uv 这么做的目的是为了能够进行group by嘛?
点赞 回复 分享
发布于 2023-02-05 16:14 北京
您好大佬,新用户定义后202001的new_day 是1, 202002的new_day是0,为什么汇总以后20202也是2呢
点赞 回复 分享
发布于 2022-11-16 10:52 北京
好机智
点赞 回复 分享
发布于 2022-10-30 17:42 山东

相关推荐

12-24 20:44
武汉大学 Java
点赞 评论 收藏
分享
12-14 11:43
黑龙江大学 Java
用微笑面对困难:确实比较烂,可以这么修改:加上大学的qs排名,然后大学简介要写一些,然后硕士大学加大加粗,科研经历第一句话都写上在复旦大学时,主要负责xxxx,简历左上角把学校logo写上,建议用复旦大学的简历模板
点赞 评论 收藏
分享
评论
129
15
分享

创作者周榜

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