记录思路过程。

思路的草稿(不是正确答案):找到每个用户的最小登录月后, 再根据最小登录月分组计数, 就能知道每个月份的新增用户数。

SELECT DATE_FORMAT(start_time, '%Y%m') start_month, COUNT(DISTINCT uid) mau,
COUNT(uid) over (PARTITION BY DATE_FORMAT(min_st,'%Y%m')) month_add_uv,
MAX(month_add_uv) OVER (ORDER BY start_month),
SUM(month_add_uv) OVER (ORDER BY start_month)
FROM 
(SELECT uid, MIN(start_time) min_st FROM exam_record GROUP BY uid) t1
GROUP BY start_month
ORDER BY start_month

month_add_uv得先算出来,然后才能在表中选择MAX(month_add_uv)/SUM(month_add_uv) OVER (ORDER BY start_month),意味着要多一层嵌套。

思路中的COUNT(uid) over (PARTITION BY DATE_FORMAT(min_st,'%Y%m')) month_add_uv意思是这么个意思,但是不能这么写。因为写的是按照start_month分组,COUNT(uid) over (PARTITION BY DATE_FORMAT(min_st,'%Y%m')) 选择这样的列是无效的,而该列没有包含在聚合函数或 GROUP BY 子句中。后面就改写成了t3表的形式。 正确答案:

SELECT start_month, mau, IFNULL(month_add_uv,0) month_add_uv,
MAX(month_add_uv) OVER (ORDER BY start_month),
SUM(month_add_uv) OVER (ORDER BY start_month)
FROM (SELECT DATE_FORMAT(start_time, '%Y%m') start_month, COUNT(DISTINCT exam_record.uid) mau
      FROM exam_record 
      GROUP BY start_month) t2
      LEFT JOIN
      (SELECT min_st, COUNT(uid) month_add_uv FROM
      (SELECT uid, DATE_FORMAT(MIN(start_time),'%Y%m') min_st FROM exam_record GROUP BY uid) t1
      GROUP BY min_st) t3
      ON t2.start_month=t3.min_st
      
ORDER BY start_month;

第一,要用start_month做连接(我开始用的是什么uid做连接,捂脸)。

第二,用上左连接,不然没有新增用户的月份会被内连接吃掉。

第三,最外层用IFNULL(month_add_uv,0),因为左连接后,没有新增用户的月份数量被记成了None,需要处理一下。用处理前的month_add_uv,算MAX(month_add_uv)/SUM(month_add_uv) OVER (ORDER BY start_month) 不影响结果,因为算的时候会忽略空值而且第一条数据不会是空值。