SQL173 月均完成试卷数不小于3的用户爱作答的类别

描述

现有试卷作答记录表exam_record(uid:用户ID, exam_id:试卷ID, start_time:开始作答时间, submit_time:交卷时间,没提交的话为NULL, score:得分),示例数据如下:

iduidexam_idstart_timesubmit_timescore
1100190012021-07-02 09:01:01(NULL)(NULL)
2100290032021-09-01 12:01:012021-09-01 12:21:0160
3100290022021-09-02 12:01:012021-09-02 12:31:0170
4100290012021-09-05 19:01:012021-09-05 19:40:0181
5100290022021-07-06 12:01:01(NULL)(NULL)
6100390032021-09-07 10:01:012021-09-07 10:31:0186
7100390032021-09-08 12:01:012021-09-08 12:11:0140
8100390012021-09-08 13:01:01(NULL)(NULL)
9100390022021-09-08 14:01:01(NULL)(NULL)
10100390032021-09-08 15:01:01(NULL)(NULL)
11100590012021-09-01 12:01:012021-09-01 12:31:0188
12100590022021-09-01 12:01:012021-09-01 12:31:0188
13100590022021-09-02 12:11:012021-09-02 12:31:0189

试卷信息表examination_info(exam_id:试卷ID, tag:试卷类别, difficulty:试卷难度, duration:考试时长, release_time:发布时间),示例数据如下:

idexam_idtagdifficultydurationrelease_time
19001SQLhard602020-01-01 10:00:00
29002C++easy602020-02-01 10:00:00
39003算法medium802020-08-02 10:00:00

有一批用户做试卷较多,他们会在一个月内(试卷的开始和结束时间都在同一个月)做三张及以上(≥3)试卷,公司准备统计这些用户喜欢做的试卷的类别,以及每个类别中所有用户一共作答的次数,按照次数降序输出,示例输出如下:

tagtag_cnt
C++4
SQL2
算法1

解释:用户1002和1005在2021年09月的完成试卷数目均为3,其他用户均小于3;然后用户1002和1005作答过的试卷tag分布结果按作答次数降序排序依次为C++、SQL、算法。

 -- 第一步:找出在某个月完成 ≥3 次且 start/submit 在同一个月的用户
WITH
    active_users AS (
        SELECT
            er.uid
        FROM
            exam_record er
            JOIN examination_info ei USING (exam_id)
        WHERE
            er.submit_time IS NOT NULL
            AND DATE_FORMAT(er.start_time, '%Y-%m') = DATE_FORMAT(er.submit_time, '%Y-%m')
        GROUP BY
            er.uid,
            DATE_FORMAT(er.start_time, '%Y-%m')
        HAVING
            COUNT(*) >= 3
    )
    -- 第二步:统计这些用户所有作答过的试卷的 tag 次数
SELECT
    ei.tag,
    COUNT(*) AS tag_cnt
FROM
    exam_record er
    JOIN examination_info ei USING (exam_id)
WHERE
    er.uid IN (
        SELECT
            uid
        FROM
            active_users
    )
GROUP BY
    ei.tag
ORDER BY
    tag_cnt DESC;

🔍 分步解析

✅ Step 1:定义 CTE —— active_users

WITH active_users AS (
    SELECT er.uid
    FROM exam_record er
    JOIN examination_info ei USING (exam_id)
    WHERE 
        er.submit_time IS NOT NULL                -- 只看“已完成”的考试
        AND DATE_FORMAT(er.start_time, '%Y-%m') = DATE_FORMAT(er.submit_time, '%Y-%m')  -- 同月完成
    GROUP BY er.uid, DATE_FORMAT(er.start_time, '%Y-%m')  -- 按用户+月份分组
    HAVING COUNT(*) >= 3                          -- 某月完成 ≥3 次
)

📌 关键点

  • GROUP BY uid, 月份:确保是“某个月”完成 3 次
  • IN (SELECT uid FROM active_users):只要用户在任意一个月满足条件,就算活跃用户
  • JOIN examination_info:虽然这里没用到 tag,但 USING(exam_id) 无副作用

✅ 正确!即使 ei 在 CTE 中未使用字段,也不影响结果。


✅ Step 2:统计这些用户所有作答的 tag

SELECT
    ei.tag,
    COUNT(*) AS tag_cnt
FROM exam_record er
JOIN examination_info ei USING (exam_id)
WHERE er.uid IN (SELECT uid FROM active_users)  -- 筛选活跃用户
GROUP BY ei.tag
ORDER BY tag_cnt DESC;

📌 关键点

  • 这里统计的是 所有作答记录(包括 submit_time IS NULL 的未完成)
  • 因为外层 exam_record 没有加 submit_time IS NOT NULL
  • 所以是“这些活跃用户接触过的所有试卷类型”
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值