题目主要信息:
- 当有 0 级用户未完成试卷数大于 2 时输出每个 0 级用户的试卷未完成数和未完成率(保留3位小数)
- 若不存在这样的用户,则输出所有有作答记录的用户的这两个指标
- 结果按未完成率升序排序
问题拆解:
- 通过 WITH AS 语句筛选出未完成试卷数大于 2 的 0 级用户,并判断这类用户是否存在。知识点:IS NULL, COUNT, HAVING, WITH AS
- 通过 WHERE 语句判断 level=0 且 submit_time IS NULL
- 基于 uid 对符合条件的 exam_record 进行聚合,统计 COUNT(1) 作为该用户的未完成试卷总数
- 使用 HAVING 语句筛选出未完成试卷总数大于 2 的用户
- 最终统计符合要求的用户数量存入临时表
- 统计所有用户的未完成数、未完成率信息,通过 WITH AS 存入临时表。知识点:LEFT JOIN, IS NOT NULL, IF, SUM, COUNT
- 将 user_info LEFT JOIN exam_record 获得总表
- 基于 uid 对总表数据进行聚合统计,IF(submit_time IS NULL AND start_time IS NOT NULL, 1, 0) 判断该记录是否未完成,对其进行 SUM 操作得到未完成总数。
- COUNT(1) 获得用户的总提交数,二者做除法获得未完成率。
- 通过 JOIN 获取上述两表的笛卡尔积,根据表一中的条件判断展现哪部分用户的汇总信息。此时需要通过 ROUND 对未完成率保留三位小数。知识点:JOIN, ORDER BY, ROUND
代码:
WITH target_user AS (
SELECT user_info.uid, COUNT(1) AS incomplete_cnt
FROM exam_record LEFT JOIN user_info
ON exam_record.uid = user_info.uid
WHERE user_info.level = 0 AND submit_time IS NULL
GROUP BY user_info.uid
HAVING incomplete_cnt > 2
), target_user_exist AS (SELECT COUNT(1) AS `exist` FROM target_user)
, total_summary AS (
SELECT
user_info.uid,
MAX(user_info.level) AS level,
SUM(IF(submit_time IS NULL AND start_time IS NOT NULL, 1, 0)) AS incomplete_cnt,
SUM(IF(submit_time IS NULL AND start_time IS NOT NULL, 1, 0)) / COUNT(1) AS incomplete_rate,
SUM(IF(start_time IS NOT NULL, 1, 0)) AS has_submit
FROM user_info LEFT JOIN exam_record
ON user_info.uid = exam_record.uid
GROUP BY user_info.uid
)
SELECT
uid,
incomplete_cnt,
ROUND(incomplete_rate, 3)
FROM total_summary LEFT JOIN target_user_exist ON 1=1
WHERE (exist=0 AND has_submit>0) OR (exist=1 AND level=0)
ORDER BY incomplete_rate ASC