思路:使用一维表的思维,将试卷和答题结合起来,且区分来源,这样既可以方便计算总量,也方便根据类别计算。

select
    uid,
    count(distinct act_month) as act_month_total,
    count(distinct case when year(act_days) = '2021' then act_days end) as act_days_2021,
    count(distinct case when year(act_days) = '2021' and tag = 'exam' then act_days end) as act_days_2021_exa,
    count(distinct case when year(act_days) = '2021' and tag = 'question' then act_days end) as act_days_2021_questi
from(
    select uid
    from user_info
    where `level` = 6 or `level` = 7
    ) as t0
left join(
        select 
            uid, 
            date_format(start_time, '%Y%m') as act_month,
            date_format(start_time, '%Y%m%d') as act_days,
            'exam' as tag
        from exam_record
        union
        select
            uid,
            date_format(submit_time, '%Y%m') as act_month,
            date_format(submit_time, '%Y%m%d') as act_days,
            'question' as tag
        from practice_record
        ) as t1
using (uid)
group by uid
order by act_month_total desc, act_days_2021 desc

这个题由于是几个月前单独做过,忘记了下面的是自己写的还是评论区里趴的了,下面的这个思路更符合实际工作中的撰写方式,根据需要增删字段,理解和修改起来都简单很多。

-- 一个问题,试卷活跃最好以start_time为基准(结果能通过)
select 
    uid, 
    if(act_month_total is null, 0, act_month_total), 
    if(act_days_2021 is null, 0, act_days_2021), 
    if(act_days_2021_exa is null, 0, act_days_2021_exa), 
    if(act_days_2021_questi is null, 0, act_days_2021_questi)
from(
    select uid
    from user_info
    where `level` = 6 or `level` = 7
    ) as t0
left join(
        -- 总活跃月数
        select uid, count(distinct date_format(submit_time, '%Y%m')) as act_month_total 
        from(
            -- id为主键,重复是否会报错,是否要指定必要列合并(列不同无法合并)
            select uid, submit_time
            from exam_record 
            union
            select uid, submit_time
            from practice_record
            ) as t1
        group by uid
        ) as t1
using(uid)
left join(
        -- 2021年活跃天数
        select uid, count(distinct date_format(submit_time, '%Y%m%d')) as act_days_2021
        from(
            select uid, submit_time
            from exam_record 
            union
            select uid, submit_time
            from practice_record
            ) as t1
        where year(submit_time) = '2021'
        group by uid
        ) as t2
using(uid)
left join(
        -- 2021年试卷作答活跃天数
        select uid, count(distinct date_format(start_time, '%Y%m%d')) as act_days_2021_exa
        from exam_record
        where year(start_time) = '2021'
        group by uid
        ) as t3
using(uid)
left join(
        -- 2021年答题活跃天数
        select uid, count(distinct date_format(submit_time, '%Y%m%d')) as act_days_2021_questi
        from practice_record
        where year(submit_time) = '2021'
        group by uid
        ) as t4
using(uid)
order by act_month_total desc, act_days_2021 desc