SQL168 统计作答次数
描述
有一个试卷作答记录表exam_record,请从中统计出总作答次数total_pv、试卷已完成作答数complete_pv、已完成的试卷数complete_exam_cnt。
示例数据 exam_record表(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
示例输出:
解释:表示截止当前,有11次试卷作答记录,已完成的作答次数为7次(中途退出的为未完成状态,其交卷时间和份数为NULL),已完成的试卷有9001和9002两份。
selectcount(exam_id) as total_pv,count(submit_time) as complete_pv,count(distinct if(submit_time is not null, exam_id, null)) as complete_exam_cnt
fromexam_record
重点解析:COUNT(DISTINCT IF(...))
用法
让我们深入讲解这个复杂的表达式:
COUNT(DISTINCT IF(submit_time IS NOT NULL, exam_id, NULL)) AS complete_exam_cnt
🎯 最终目的
统计有多少种不同的试卷被成功完成过
🔍 逐步拆解
第一步:理解 IF
函数
IF(submit_time IS NOT NULL, exam_id, NULL)
这是一个条件判断函数,相当于Excel中的IF函数:
条件 | 结果 |
---|---|
如果 submit_time 不为空 | 返回 exam_id |
如果 submit_time 为空 | 返回 NULL |
💡 简单说:只保留那些"已完成考试"的记录,未完成的标记为NULL
第二步:DISTINCT
去重
DISTINCT IF(...)
- 只保留唯一的、非NULL的值
- 相同的
exam_id
只算一次 - 所有的
NULL
值被忽略
第三步:COUNT
计数
COUNT(...)
统计去重后非NULL值的数量。
📊 实际执行过程
假设原始数据:
exam_id | submit_time |
---|---|
101 | 2023-01-01 10:00 |
101 | 2023-01-01 11:00 |
102 | NULL |
103 | 2023-01-02 09:00 |
103 | 2023-01-02 10:00 |
103 | 2023-01-02 11:00 |
执行步骤:
应用IF函数:
101 (因为submit_time不为空) 101 (因为submit_time不为空) NULL (因为submit_time为空) 103 (因为submit_time不为空) 103 (因为submit_time不为空) 103 (因为submit_time不为空)
DISTINCT去重:
101 103 NULL (NULL被忽略)
COUNT计数:
- 非NULL的唯一值有2个:101和103
- 结果:2
💡 为什么这样设计?
这种写法巧妙地解决了三个问题:
- 过滤未完成的考试(通过IF判断)
- 去重(相同试卷ID只算一次)
- 排除NULL值(未完成的记录不计入)