明确题意:

当有0级用户未完成试卷数大于2时输出每个0级用户的试卷未完成数和未完成率(保留3位小数); 若不存在这样的用户,则输出所有有作答记录的用户的这两个指标。

结果按未完成率升序排序。


问题分解:

  • 统计每个用户的等级、未完成数、未完成率和总作答数,生成临时表 t_tag_count:
    • 右连接试卷作答表和用户信息表:exam_record RIGHT JOIN user_info USING(uid)
    • 按用户分组:GROUP BY uid
    • 统计未完成数:COUNT(start_time) - COUNT(submit_time) as incomplete_cnt
    • 统计未完成率:IFNULL(1 - COUNT(submit_time) / COUNT(start_time), 0) as incomplete_rate
      • 保留3位小数:ROUND(x, 3)
    • 统计总作答数:COUNT(start_time) as total_cnt
  • 当存在0级用户未完成试卷数大于2时:
    • 筛选存在性条件:WHERE EXISTS (SELECT uid FROM t_tag_count WHERE level = 0 AND incomplete_cnt > 2)
    • 输出每个0级用户的试卷未完成数和未完成率:
      • 筛选0级用户:level = 0
      • SELECT uid, incomplete_cnt, incomplete_rate
  • 当不存在0级用户未完成试卷数大于2时:
    • 筛选存在性条件:WHERE NOT EXISTS (SELECT uid FROM t_tag_count WHERE level = 0 AND incomplete_cnt > 2)
    • 输出所有有作答记录的用户的这两个指标:
      • 筛选有作答记录的用户:total_cnt > 0
      • SELECT uid, incomplete_cnt, incomplete_rate
  • 合并上述结果,条件互斥,so只可能有一个结果集:UNION ALL

细节问题:

  • 表头重命名:as
  • 按未完成率升序排序:ORDER BY incomplete_rate

完整代码:

WITH t_tag_count as (
    SELECT uid, `level`,
        COUNT(start_time) - COUNT(submit_time) as incomplete_cnt, -- 未完成数
        ROUND(
            IFNULL(1 - COUNT(submit_time) / COUNT(start_time), 0),
            3) as incomplete_rate, -- 此人未完成率
        COUNT(start_time) as total_cnt -- 总作答数
    FROM exam_record
    RIGHT JOIN user_info USING(uid)
    GROUP BY uid
)

SELECT uid, incomplete_cnt, incomplete_rate
FROM t_tag_count
WHERE EXISTS (
    SELECT uid FROM t_tag_count WHERE `level` = 0 AND incomplete_cnt > 2
) AND `level` = 0
UNION ALL
SELECT uid, incomplete_cnt, incomplete_rate
FROM t_tag_count
WHERE NOT EXISTS (
    SELECT uid FROM t_tag_count WHERE `level` = 0 AND incomplete_cnt > 2
) AND total_cnt > 0
ORDER BY incomplete_rate;