【难度】:经典题

【场景】:计算结果不同输出结果不同

【分类】:高级条件语句、if(select 语句)、where or(条件不同时满足)、where if/case when(根据计算结果输出不同条件)

分析思路

难点:

1.计算结果不同输出结果不同

收获:

1.if()里面也可以嵌套select子句

2.where or(两个条件不会同时满足,相当于执行or的左边否则执行右边)

3.left join 中使用 on 1 = 1,连接条件 1 = 1 表示无条件的 left join,它返回来自左表表达式的所有行,即使在右表表达式中没有匹配。

4.where 里面使用 if,根据是否存在 ‘未完成试卷数大于2的用户’ ,得到其他条件,进而确定输出结果。

(1)当有任意一个0级用户未完成试卷数大于2

因为输出用户以user_info表为主

  • [使用]:左连接 left join

  • [条件]:level = 0 and count(incomplete_cnt) > 2

计算每个用户的试卷未完成数:

  • [使用]:sum(if(uid in (select uid from exam_record) and submit_time is null,1,0))

未完成率:

  • [使用]:count(if(submit_time is null,1,null)/count(start_time)

(2)若不存在这样的用户

输出用户以exam_record表为主

  • [使用]:右连接 right join

计算每个用户的试卷未完成数:

  • [使用]:count(if(submit_time is null,1,null))

未完成率:

  • [使用]:count(if(submit_time is null,1,null)/count(start_time)

(3)根据指定记录是否存在输出不同情况,并按未完成率升序输出

  • [使用]:sum(incomplete_cnt) > 0

求解代码

方法一:

with子句 + if(select )

with
    main as(
        #当有任意一个0级用户未完成试卷数大于2,其未完成数和未完成率
        select
            a.uid,
            sum(if(uid in (select uid from exam_record) and submit_time is null,1,0)) as incomplete_cnt,
            round(if(count(start_time) = 0,0,count(if(submit_time is null,1,null))/count(start_time)),3) as incomplete_rate
        from user_info a
        left join exam_record using(uid)
        where level = 0
        group by uid 
        order by incomplete_rate
    )
    ,attr as(
        #不存在0级用户未完成试卷数大于2,其未完成数和未完成率
        select
            b.uid,
            count(if(submit_time is null,1,null)) as incomplete_cnt,
            round(if(count(start_time) = 0,0,count(if(submit_time is null,1,null))/count(start_time)),3) as incomplete_rate
        from user_info a
        right join exam_record b using(uid)
        group by uid
        order by incomplete_rate
    )
#根据指定记录是否存在输出不同情况,并按未完成率升序输出
select distinct
    if((select sum(incomplete_cnt) from main where incomplete_cnt > 2) > 0,a.uid,b.uid) as uid,
    if((select sum(incomplete_cnt) from main where incomplete_cnt > 2) > 0,a.incomplete_cnt,b.incomplete_cnt) as incomplete_cnt,
    if((select sum(incomplete_cnt) from main where incomplete_cnt > 2) > 0,a.incomplete_rate,b.incomplete_rate) as incomplete_rate
from main a, attr b
order by incomplete_rate

方法二:

where or(两个条件不会同时满足,相当于执行or的左边否则执行右边)

left join 中使用 on 1 = 1,连接条件 1 = 1 表示无条件的 left join,它返回来自左表表达式的所有行,即使在右表表达式中没有匹配。

select
    a.uid,
    if(attr.incomplete_cnt is null,0,attr.incomplete_cnt) as incomplete_cnt,
    if(round(attr.incomplete_rate,3) is null,0,round(attr.incomplete_rate,3)) as incomplete_rate
from user_info a
left join(
    #不存在0级用户未完成试卷数大于2,其未完成数和未完成率
    select 
        uid,
        sum(if(uid in (select uid from exam_record) and submit_time is null,1,0)) as incomplete_cnt,
        round(if(count(start_time) = 0,0,count(if(submit_time is null,1,null))/count(start_time)),3) as incomplete_rate
    from exam_record
    group by uid 
) attr on a.uid = attr.uid
left join(
    #当有任意一个0级用户未完成试卷数大于2,其未完成数和未完成率
    select
        b.uid
    from exam_record b
    left join user_info a on a.uid=b.uid
    where level=0
    group by uid
    having sum(case when submit_time is null then 1 else 0 end) >= 2
) main on 1 = 1
where (main.uid is not null) or (main.uid is null and attr.uid is not null) #两个条件不会同时满足,所以可以使用 or
order by incomplete_rate

方法三:

where 里面使用 if,根据是否存在 ‘未完成试卷数大于2的用户’ ,得到其他条件,进而确定输出结果。

如果 ‘ 未完成试卷数大于2’ 的用户 不存在,条件是 ’用户的作答记录不为空‘ ,否则得到 ’用户等级为 0‘。

select
    a.uid,
    count(b.uid is not null and score is null or null) as incomplete_cnt,
    round(count(b.uid is not null and score is null or null)/if(count(b.uid)=0,1,count(b.uid)),3) as incomplete_rate
from user_info a
left join exam_record b on a.uid = b.uid
where if((
    #当有任意一个0级用户未完成试卷数大于2,输出每个0级用户的试卷未完成数和未完成率;若不存在这样的用户,则输出所有有作答记录的用户的这两个指标
    select
        count(*)
    from exam_record c
    left join user_info d using(uid)
    where score is null and level=0
    group by uid
    having count(*) > 2
    limit 1) is null,
    b.uid is not null,
    a.level=0
)
group by uid
order by incomplete_rate