明确题意:

请统计每个6/7级用户总活跃月份数、2021年活跃天数、2021年试卷作答活跃天数、2021年答题活跃天数,按照总活跃月份数、2021年活跃天数降序排序。


问题分解:

  • 统计每个用户的总活跃月份数、2021年活跃天数,生成子表 t_2021_total_act:
    • 统计每个用户的每天活跃情况,生成子表 t_merge_record :
      • 统计试卷区用户活跃情况:distinct uid, DATE(start_time) as active_date
      • 统计试题区用户活跃情况:distinct uid, DATE(submit_time) as active_date
      • 合并上述活跃情况:UNION ALL
    • 按用户分组:GROUP BY uid
    • 统计总活跃月份数:COUNT(distinct DATE_FORMAT(active_date, "%Y%m")) as act_month_total
    • 统计2021年活跃天数:COUNT(distinct if(YEAR(active_date)=2021, active_date, null)) as act_days_2021
  • 统计2021年题目练习活跃天数,生成子表 t_2021_act_days_question:
    • 筛选2021年的记录:WHERE YEAR(submit_time)=2021
    • 按用户分组:GROUP BY uid
    • 统计活跃天数:COUNT(distinct DATE(submit_time)) as act_days_2021_question
  • 统计2021年试卷作答活跃天数,生成子表 t_2021_act_days_exam:
    • 筛选2021年的记录:WHERE YEAR(start_time)=2021
    • 按用户分组:GROUP BY uid
    • 统计活跃天数:COUNT(distinct DATE(start_time)) as act_days_2021_exam
  • 左连接user_info和上述3个子表(左连接是因为题目要求输出每个满足属性条件的用户的各类指标,即使都为0):
  • 筛选用户级别:WHERE user_info.level > 5
  • 特殊处理指标为0的情况,为0时左连接结果会是NULL:ifnull(act_month_total, 0) as act_month_total (其他指标写法一样)

细节问题:

  • 表头重命名:as
  • 按总活跃月份数、2021年活跃天数降序排序:ORDER BY act_month_total DESC, act_days_2021 DESC

完整代码:

SELECT user_info.uid as uid,
    ifnull(act_month_total, 0) as act_month_total,
    ifnull(act_days_2021, 0) as act_days_2021,
    ifnull(act_days_2021_exam, 0) as act_days_2021_exam,
    ifnull(act_days_2021_question, 0) as act_days_2021_question
FROM user_info
LEFT JOIN (
    SELECT uid,
        COUNT(distinct DATE_FORMAT(active_date, "%Y%m")) as act_month_total,
        COUNT(distinct if(YEAR(active_date)=2021, active_date, null)) as act_days_2021
    FROM (
        SELECT distinct uid, DATE(start_time) as active_date FROM exam_record
        UNION ALL
        SELECT distinct uid, DATE(submit_time) as active_date FROM practice_record
    ) as t_merge_record
    GROUP BY uid
) AS t_2021_total_act USING(uid) -- 总活跃月份数、2021年活跃天数
LEFT JOIN (
    SELECT uid, COUNT(distinct DATE(submit_time)) as act_days_2021_question
    FROM practice_record
    WHERE YEAR(submit_time)=2021
    GROUP BY uid
) as t_2021_act_days_question USING(uid) -- 2021年题目练习活跃天数
LEFT JOIN (
    SELECT uid, COUNT(distinct DATE(start_time)) as act_days_2021_exam
    FROM exam_record
    WHERE YEAR(start_time)=2021
    GROUP BY uid
) as t_2021_act_days_exam USING(uid) -- 2021试卷作答活跃天数
WHERE user_info.level > 5
ORDER BY act_month_total DESC, act_days_2021 DESC;