SQL176 每个题目和每份试卷被作答的人数和次数
描述
现有试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):
id | uid | exam_id | start_time | submit_time | score |
1 | 1001 | 9001 | 2021-09-01 09:01:01 | 2021-09-01 09:41:01 | 81 |
2 | 1002 | 9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 | 70 |
3 | 1002 | 9001 | 2021-09-01 19:01:01 | 2021-09-01 19:40:01 | 80 |
4 | 1002 | 9002 | 2021-09-01 12:01:01 | 2021-09-01 12:31:01 | 70 |
5 | 1004 | 9001 | 2021-09-01 19:01:01 | 2021-09-01 19:40:01 | 85 |
6 | 1002 | 9002 | 2021-09-01 12:01:01 | (NULL) | (NULL) |
题目练习表practice_record(uid用户ID, question_id题目ID, submit_time提交时间, score得分):
id | uid | question_id | submit_time | score |
1 | 1001 | 8001 | 2021-08-02 11:41:01 | 60 |
2 | 1002 | 8001 | 2021-09-02 19:30:01 | 50 |
3 | 1002 | 8001 | 2021-09-02 19:20:01 | 70 |
4 | 1002 | 8002 | 2021-09-02 19:38:01 | 70 |
5 | 1003 | 8001 | 2021-08-02 19:38:01 | 70 |
6 | 1003 | 8001 | 2021-08-02 19:48:01 | 90 |
7 | 1003 | 8002 | 2021-08-01 19:38:01 | 80 |
请统计每个题目和每份试卷被作答的人数和次数,分别按照"试卷"和"题目"的uv & pv降序显示,示例数据结果输出如下:
tid | uv | pv |
9001 | 3 | 3 |
9002 | 1 | 3 |
8001 | 3 | 5 |
8002 | 2 | 2 |
解释:“试卷”有3人共练习3次试卷9001,1人作答3次9002;“刷题”有3人刷5次8001,有2人刷2次8002
SELECTexam_id AS tid,COUNT(DISTINCT exam_record.uid) uv,COUNT(*) pv
FROMexam_record
GROUP BYexam_id
UNION
SELECTquestion_id AS tid,COUNT(DISTINCT practice_record.uid) uv,COUNT(*) pv
FROMpractice_record
GROUP BYquestion_id
ORDER BYLEFT(tid, 1) DESC,uv DESC,pv DESC;
🔍 分步拆解与核心知识点
🧱 第一部分:考试行为统计(Exam UV/PV)
SELECTexam_id AS tid,COUNT(DISTINCT uid) AS uv,COUNT(*) AS pv
FROM exam_record
GROUP BY exam_id
字段 | 说明 |
---|---|
exam_id AS tid | 统一别名为 tid (目标 ID),便于合并 |
COUNT(DISTINCT uid) | 计算该试卷的独立用户数(UV) |
COUNT(*) | 总作答次数(PV) |
GROUP BY exam_id | 按试卷分组统计 |
🧱 第二部分:练习行为统计(Question UV/PV)
SELECTquestion_id AS tid,COUNT(DISTINCT uid) AS uv,COUNT(*) AS pv
FROM practice_record
GROUP BY question_id
结构与第一部分完全一致,只是数据源不同。
🧱 合并:UNION
-- 第一个查询
...
UNION
-- 第二个查询
- ✅
UNION
将两个结构相同的查询结果纵向拼接 - 要求:各列类型和顺序必须一致(这里都是
tid
,uv
,pv
) - 自动去重(如用
UNION ALL
则不去重)
🧱 排序:ORDER BY LEFT(tid, 1) DESC, uv DESC, pv DESC
ORDER BYLEFT(tid, 1) DESC, -- 按 tid 的第一个字符降序uv DESC,pv DESC