通过代码1

with t as (
SELECT
    u_i.uid,
    level,
    tag,
    if(u_i.uid not in (SELECT uid FROM exam_record),0,incomplete_cnt) incomplete_cnt,
    round(if(u_i.uid not in (SELECT uid FROM exam_record),0,incomplete_rate),3) incomplete_rate
FROM
    user_info u_i
LEFT JOIN(
SELECT
    uid,
    sum(if(score is NULL,1,0)) incomplete_cnt,
    sum(if(score is NULL,1,0)) / count(*) incomplete_rate,
    '1' tag
FROM
    exam_record
GROUP BY
    uid) e
ON
    u_i.uid = e.uid
GROUP BY
    u_i.uid
)


SELECT 
    uid,
    incomplete_cnt,
    incomplete_rate
FROM
    t 
where EXISTS(
    select 
     uid 
 from 
     t 
 where 
     level=0 and incomplete_cnt>2
) and level = 0

union all

SELECT 
    uid,
    incomplete_cnt,
    incomplete_rate
FROM
    t 
where not EXISTS(
    select 
     uid 
 from 
     t 
 where 
     level=0 and incomplete_cnt>2
) and tag = '1'
order by 
    incomplete_rate

思路

先上题目要求:筛选表中的数据,当有任意一个0级用户未完成试卷数大于2时输出每个0级用户的试卷未完成数和未完成率(保留3位小数);若不存在这样的用户,则输出所有有作答记录的用户的这两个指标。结果按未完成率升序排序。另外未作答过试卷,未完成率默认填0,保留3位小数后是0.000

我们先干嘛呢?我觉得首先得把exam_record中的相应指标查并标记不然到时候我们怎么知道那些是有作答记录的用户呢?未完成数目和未完成率为0显然不能证明他没有作答记录


1.有作答记录筛选

SELECT
    uid,
    sum(if(score is NULL,1,0)) incomplete_cnt,
    sum(if(score is NULL,1,0)) / count(*) incomplete_rate,
    '1' tag
FROM
    exam_record
GROUP BY
    uid

给了一个1作为tag记录


2.无作答记录并入表一

SELECT
    u_i.uid,
    level,
    tag,
    if(u_i.uid not in (SELECT uid FROM exam_record),0,incomplete_cnt) incomplete_cnt,
    round(if(u_i.uid not in (SELECT uid FROM exam_record),0,incomplete_rate),3) incomplete_rate
FROM
    user_info u_i
LEFT JOIN(
GROUP BY(1.代码) e
ON
    u_i.uid = e.uid
GROUP BY
    u_i.uid

这里我用了not in 手动置零,现在这个表里tag为1就是有作答记录的人。


3.当……这样,否则那样

SELECT 
    uid,
    incomplete_cnt,
    incomplete_rate
FROM
    t 
where EXISTS(
    select 
     uid 
 from 
     t 
 where 
     level=0 and incomplete_cnt>2
) and level = 0
union all
SELECT 
    uid,
    incomplete_cnt,
    incomplete_rate
FROM
    t 
where not EXISTS(
    select 
     uid 
 from 
     t 
 where 
     level=0 and incomplete_cnt>2
) and tag = '1'
order by 
    incomplete_rate

因为我没看过书,就直接做题遇到不会的再学习,所以这里就是对我来说的新知识:where exists

EXISTS执行顺序:

1、首先执行一次外部查询,并缓存结果集,如 SELECT * FROM A

2、遍历外部查询结果集的每一行记录R,代入子查询中作为条件进行查询,如 SELECT 1 FROM B WHERE B.id = A.id

3、如果子查询有返回结果,则EXISTS子句返回TRUE,这一行R可作为外部查询的结果行,否则不能作为结果

对这个题就是如果level=0 and incomplete_cnt>2 那就筛选level = 0的输出

这里没有否则,就是如果这里不成立这一段就不会执行了 所以需要来一个union all 就是如果不,就筛出tag = 1就行。


通过代码2

with t as 
(
select 
    t.uid,
    level,
    sum(if(start_time is not null and submit_time is null,1,0))  incomplete_cnt,
    round(sum(if(start_time is not null and submit_time is null,1,0))/count(1),3)  incomplete_rate,
    count(exam_id)  num
from 
    user_info t
left join 
    exam_record t1 on t.uid = t1.uid
group by 
    t.uid
)

select 
    uid,
    incomplete_cnt,
    incomplete_rate
from 
    t
where EXISTS 
(select 
     uid 
 from 
     t 
 where 
     level=0 and incomplete_cnt>2
) and level=0

union ALL

select 
    uid,
    incomplete_cnt,
    incomplete_rate
from 
    t
where not EXISTS (
    select 
        uid 
    from 
        t 
    where 
        level=0 and incomplete_cnt>2
) and num>0
order by 
    incomplete_rate

上边那个是拆题来的,就是没有任何优化或者设计,直接题怎么出我怎么来,所以就有了这个,但是基本道理还是一样的。