首页 > 试题广场 >

未完成试卷数大于1的有效用户

[编程题]未完成试卷数大于1的有效用户
  • 热度指数:135272 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
现有试卷作答记录表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-07-02 09:01:01
2021-07-02 09:21:01
80
2 1002
9001
2021-09-05 19:01:01
2021-09-05 19:40:01
81
3 1002
9002
2021-09-02 12:01:01
(NULL) (NULL)
4 1002
9003
2021-09-01 12:01:01
(NULL)
(NULL)
5 1002
9001
2021-07-02 19:01:01
2021-07-02 19:30:01
82
6 1002
9002
2021-07-05 18:01:01
2021-07-05 18:59:02
90
7 1003
9002
2021-07-06 12:01:01
(NULL)
(NULL)
8 1003
9003
2021-09-07 10:01:01
2021-09-07 10:31:01
86
9 1004
9003
2021-09-06 12:01:01
(NULL)
(NULL)
10 1002
9003
2021-09-01 12:01:01
2021-09-01 12:31:01
81
11 1005
9001
2021-09-01 12:01:01
2021-09-01 12:31:01
88
12 1005
9002
2021-09-01 12:01:01
2021-09-01 12:31:01
88
13 1006
9002
2021-09-02 12:11:01
2021-09-02 12:31:01
89

还有一张试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间),示例数据如下:
id exam_id tag difficulty duration
release_time
1 9001 SQL hard 60 2020-01-01 10:00:00
2 9002 SQL easy
60
2020-02-01 10:00:00
3 9003
算法
medium
80
2020-08-02 10:00:00

请统计2021年每个未完成试卷作答数大于1的有效用户的数据(有效用户指完成试卷作答数至少为1且未完成数小于5),输出用户ID、未完成试卷作答数、完成试卷作答数、作答过的试卷tag集合,按未完成试卷数量由多到少排序。示例数据的输出结果如下:
uid incomplete_cnt complete_cnt
detail
1002 2 4 2021-09-01:算法;2021-07-02:SQL;2021-09-02:SQL;2021-09-05:SQL;2021-07-05:SQL
解释:2021年的作答记录中,除了1004,其他用户均满足有效用户定义,但只有1002未完成试卷数大于1,因此只输出1002,detail中是1002作答过的试卷{日期:tag}集合,日期和tag间用:连接,多元素间用;连接。
示例1

输入

drop table if exists examination_info;
CREATE TABLE examination_info (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    exam_id int UNIQUE NOT NULL COMMENT '试卷ID',
    tag varchar(32) COMMENT '类别标签',
    difficulty varchar(8) COMMENT '难度',
    duration int NOT NULL COMMENT '时长',
    release_time datetime COMMENT '发布时间'
)CHARACTER SET utf8 COLLATE utf8_general_ci;

drop table if exists exam_record;
CREATE TABLE  exam_record (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    uid int NOT NULL COMMENT '用户ID',
    exam_id int NOT NULL COMMENT '试卷ID',
    start_time datetime NOT NULL COMMENT '开始时间',
    submit_time datetime COMMENT '提交时间',
    score tinyint COMMENT '得分'
)CHARACTER SET utf8 COLLATE utf8_general_ci;

INSERT INTO examination_info(exam_id,tag,difficulty,duration,release_time) VALUES
  (9001, 'SQL', 'hard', 60, '2020-01-01 10:00:00'),
  (9002, 'SQL', 'easy', 60, '2020-02-01 10:00:00'),
  (9003, '算法', 'medium', 80, '2020-08-02 10:00:00');

INSERT INTO exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2021-07-02 09:01:01', '2021-07-02 09:21:01', 80),
(1002, 9001, '2021-09-05 19:01:01', '2021-09-05 19:40:01', 81),
(1002, 9002, '2021-09-02 12:01:01', null, null),
(1002, 9003, '2021-09-01 12:01:01', null, null),
(1002, 9001, '2021-07-02 19:01:01', '2021-07-02 19:30:01', 82),
(1002, 9002, '2021-07-05 18:01:01', '2021-07-05 18:59:02', 90),
(1003, 9002, '2021-07-06 12:01:01', null, null),
(1003, 9003, '2021-09-07 10:01:01', '2021-09-07 10:31:01', 86),
(1004, 9003, '2021-09-06 12:01:01', null, null),
(1002, 9003, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 81),
(1005, 9001, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 88),
(1005, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 88),
(1006, 9002, '2021-09-02 12:11:01', '2021-09-02 12:31:01', 89);

输出

1002|2|4|2021-07-02:SQL;2021-07-05:SQL;2021-09-01:算法;2021-09-02:SQL;2021-09-05:SQL

备注:
按未完成试卷数量由多到少排序
1. 这题不能用score去判断是否为null,不然提交的时候,有的人有成绩没提交时间(可以说真的有点令人无语)

2. 这一题如果你出现这样的情况,

通常出现这种情况就说明你的代码错了可以检查有没有用concat_ws或者concat函数将submit_time和tag连接并且同时distinct
group_concat(distinct concat_ws(':',date(start_time),tag) order by start_time separator ';')

具体的代码
# 条件1:有效用户,指完成试卷作答数至少为1且未完成数小于5
# 条件2:未完成试卷作答数大于1
# 结合得 1<未完成试卷答题数<5 , 完成试卷作答数 >= 1
# 条件3:考试开始年限为 2021年

# 输出内容:未完成试卷作答数、完成试卷作答数、作答过的试卷tag集合
# 排序:未完成试卷数量由多到少

SELECT uid,
SUM(CASE WHEN submit_time IS NULL THEN 1 ELSE 0 END) "incomplete_cnt",
SUM(CASE WHEN submit_time IS NULL THEN 0 ELSE 1 END) "complete_cnt",
group_concat(distinct concat_ws(':',date(start_time),tag) order by start_time separator ';') as detail
FROM exam_record er INNER JOIN
examination_info ei 
ON er.exam_id = ei.exam_id
WHERE year(start_time) = 2021
GROUP BY uid
HAVING complete_cnt >= 1 AND incomplete_cnt > 1 AND
incomplete_cnt < 5
ORDER BY incomplete_cnt desc







发表于 2022-02-25 16:54:57 回复(13)
STEP1:把2021年的数据筛选出来
select *
from exam_record er
left join examination_info ei
on er.exam_id=ei.exam_id
where year(er.start_time)=2021

STEP2:按uid聚合,计算incomplete_cnt和complete_cnt
select a.uid,
SUM(CASE when a.submit_time is null then 1 END) as incomplete_cnt,
SUM(CASE when a.submit_time is not null then 1 END) as complete_cnt,
GROUP_CONCAT(DISTINCT CONCAT(DATE_FORMAT(a.start_time,'%Y-%m-%d'),':',b.tag) order by start_time SEPARATOR ";") as detail
from exam_record a 
left join examination_info b 
on a.exam_id=b.exam_id
where YEAR(a.start_time)=2021
group by a.uid
STEP3:进行筛选
(1)未完成试卷数大于1 incomplete_cnt>1
(2)完成试卷数至少为1 complete_cnt>=1
(3)未完成数小于5 incomplete_cnt<5
STEP4:将日期和tag组合,函数group_concat([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] [Separator'分隔符'])

综上代码为:
select er.uid,
count(case when er.submit_time is null then er.start_time else null end) incomplete_cnt, 
count(case when er.submit_time is not null then er.start_time else null end) complete_cnt,
GROUP_CONCAT(DISTINCT DATE_FORMAT(er.submit_time,'%Y-%m-%d'),':',ei.tag) detail
from exam_record er
left join examination_info ei
on er.exam_id=ei.exam_id
where year(er.start_time)=2021
group by er.uid
having complete_cnt>=1 and incomplete_cnt<5 and incomplete_cnt>1 
order by incomplete_cnt desc;
得到的答案





发表于 2021-10-21 17:14:57 回复(10)
select er.uid,
       sum(if(submit_time is null,1,0)) as incomplete_cnt,
       sum(if(submit_time is not null,1,0)) as complete_cnt,
       group_concat(distinct concat_ws(':',date(start_time),tag) separator ';') as detail
from exam_record er left join examination_info ei on er.exam_id = ei.exam_id where year(start_time)=2021
group by er.uid
having complete_cnt>=1 and incomplete_cnt<5 and incomplete_cnt>1
order by incomplete_cnt desc;

发表于 2021-11-20 13:47:16 回复(3)
先两表连接,并将时间与tag用','合并以及筛选2021年
select uid
        ,concat_ws(':',substring(start_time,1,10),tag) as sub
        ,submit_time
from exam_record a
inner join examination_info b
on a.exam_id = b.exam_id
where year(start_time) = '2021'
第二步通过submit_time来计算完成,未完成试卷数,还有通过group_concat()来将第一步的数据通过';'合并成detial
select uid
        ,sum(if(submit_time is not null,1,0)) as complete_cnt
        ,sum(if(submit_time is null,1,0)) as incomplete_cnt
        ,group_concat(distinct sub separator ';') as detail
from(
select uid
        ,concat_ws(':',substring(start_time,1,10),tag) as sub
        ,submit_time
from exam_record a
inner join examination_info b
on a.exam_id = b.exam_id
where year(start_time) = '2021'
) cnt 
group by uid
第三步筛选出未完成试卷作答数大于1的有效用户就好,where+and筛选就行,还有排序不要忘了
select uid,incomplete_cnt,complete_cnt,detail
from(
select uid
        ,sum(if(submit_time is not null,1,0)) as complete_cnt
        ,sum(if(submit_time is null,1,0)) as incomplete_cnt
        ,group_concat(distinct sub separator ';') as detail
from(
select uid
        ,concat_ws(':',substring(start_time,1,10),tag) as sub
        ,submit_time
from exam_record a
inner join examination_info b
on a.exam_id = b.exam_id
where year(start_time) = '2021'
) cnt 
group by uid
) aa
where incomplete_cnt > 1 
and complete_cnt >= 1 and incomplete_cnt < 5
order by incomplete_cnt desc
感觉这个逻辑写的不复杂,一层套一层就好,感兴趣的可以看看,如果有更简单更直观的方法欢迎指正

发表于 2021-11-08 21:06:49 回复(2)
知识点:行转列运用的group_concat()函数,可以将多行拼接为列函数group_concat([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] [Separator'分隔符']),默认是“,”分割

第一遍写的时候犯了两个错误:1)没有对case when 后的结果进行正确聚合,然后还是sum是总计,count是计数会把包括0的一起归纳进去
2)应该先对start_time,';',tag进行拼接再用group_concat进行行转列的拼接,没认真读结果要求的格式只记得行转列的拼接了
select er.uid,
sum(case when er.submit_time is null then 1 else 0 end)as imcompelete_cnt,
sum(case when er.submit_time is not null then 1 else 0 end)as complete_cnt,
group_concat(distinct concat(date_format(er.start_time,'%Y-%m-%d'),':',e.tag) 
             order by er.start_time separator';')as detail
from exam_record er
left join examination_info e 
on er.exam_id=e.exam_id
where year(er.start_time)=2021
group by er.uid
having imcompelete_cnt>1 and complete_cnt>=1 and imcompelete_cnt<5
order by imcompelete_cnt desc


发表于 2022-01-05 19:14:58 回复(1)
select 
    t.uid,t.incomplete_cnt,t.complete_cnt
    # 进行group_concat()的时候,发现有重复记录,因此做一个去重
    ,group_concat(distinct t.new_con separator ';') as detial
from 
(
    select 
        uid,tag,start_time
        # 两个sum()窗口函数可以计算出没要记录的未完成与完成题目数,方便后续条件筛选,比较清晰
        ,sum(if(submit_time is null,1,0))over(partition by uid) as incomplete_cnt 
        ,sum(if(submit_time is not null,1,0))over(partition by uid) as complete_cnt
        ,concat(substring(start_time,1,10),':',tag) as new_con
    from exam_record t1 
    left join examination_info t2 on t1.exam_id=t2.exam_id
    where year(start_time)='2021' 
    order by start_time
) t 
where t.incomplete_cnt >1 and t.incomplete_cnt <5 and t.complete_cnt >=1 
group by t.uid
order by t.incomplete_cnt desc
此题学习的新知识点,行转列运用的group_concat()函数,可以将多行拼接为列;
思路:
1.将两张表拼接成一张临时表;
2.在临时表中运用两个sum()窗口函数可以计算出没要记录的未完成与完成题目数,方便后续条件筛选,比较清晰。也不会出现group by 带来的去重问题;
3.基于临时表,进行进一步的条件筛选,并进行group_concat()函数拼接。
还有些可以优化的地方,各位大佬多多指教~
发表于 2021-10-29 11:57:03 回复(1)
with t2 as (
select t.*,t1.tag from exam_record t 
    inner join examination_info t1 using(exam_id) where year(start_time)=2021 )



    select uid,count(submit_time  is null or null) as incomplete_cnt,count(submit_time ) as complete_cnt
    ,group_concat(distinct concat(date(start_time),':',tag) order by start_time  separator ";") as detail from t2 
    group by uid having complete_cnt>=1 and incomplete_cnt between 2 and 4
    order by complete_cnt

根据思路进行
首先想到可能表连接会多次进行,所以使用的with 临时表。

根据每个用户的情况,可以自然想到groupby uid,筛选条件都是聚合后的,所以自然想到 having。

条件1:有效用户,指完成试卷作答数至少为1且未完成数小于5 条件2:未完成试卷作答数大于1结合得 1``<未完成试卷答题数<``5 , 完成试卷作答数 >= 1
条件3:考试开始年限为2021年

主要是第三个group_concat 的使用。
group_concat( DISTINCT 要连接的字段Order BY ASC/DESC 排序字段]Separator '分隔符')

易错点:
1、这题不能用score去判断是否为null,不然提交的时候,有的人有成绩没提交时间
2、group_concat 需要使用distinct,因为有重复的
3、最后要排序
@苏打烟花无糖粉 的答案和解释,简洁有效、赞

发表于 2022-08-19 13:25:13 回复(0)
“完成试卷作答” == 提交时间 is not null
踩坑:提交了试卷不一定有分数,用分数字段计算就报错,必须用提交时间字段计算
发表于 2022-04-05 20:15:38 回复(1)
select
uid,
(count(start_time))- (count(submit_time)) as incomplete_cnt,
count( submit_time) complete_cnt,
GROUP_CONCAT(distinct concat(date_format(start_time,"%Y-%m-%d"),":",tag)
             order by start_time 
            separator ";")
from exam_record t1
left join
examination_info t2
on t1.exam_id =t2.exam_id
where year(start_time)= 2021
group by uid
having complete_cnt >=1 and incomplete_cnt < 5 and 
incomplete_cnt > 1 
order by uid desc


发表于 2021-12-31 17:34:18 回复(0)
思路:
    1、连接表:主表左连信息表
    2、确定where:筛选数据2021年
    3、根据结果,定分组:uid
    4、对每个用户进行条件判断:4.1 完成试卷数至少为1, 4.2 未完成试卷数要大于1,小于5
    5、SELECT 输出需要的结果:用户id,未完成试卷数,完成试卷数,开始答题&试卷类型
    6、排序:根据未完成试卷数降序
关键SQL:
1、完成试卷数:COUNT(submit_time) 
    COUNT()会统计非null的次数
2、未完成试卷数:COUNT(*)-COUNT(a.submit_time)
    未完成试卷数 = 总做的试卷数 - 完成的试卷数 
3、detail试卷集合{日期:tag}:GROUP_CONCAT(DISTINCT CONCAT(date_format(a.start_time,'%Y-%m-%d'),':',b.tag) ORDER BY a.start_time ASC SEPARATOR ';') AS detail
    3.1 分组的行合并,MYSQL可以使用函数 GROUP_CONCAT,SQLSERVER可以使用 STRING_AGG()
        GROUP_CONCAT([DISTINCT] 字段列 [ORDER BY 排序字段 ASC/DESC] [Separator '分隔符'])
    3.2 结果需要的时间日期类型需要处理成 yyyy-mm-dd,可以使用date_format(a.start_time,'%Y-%m-%d')
    3.3 行之间的信息连接,可以使用 CONCAT来做,CONCAT(date_format(a.start_time,'%Y-%m-%d'),':',b.tag)
    3.4 指定好排序,和分隔符

可执行SQL语句(MYSQL):
SELECT 
    a.uid AS uid,
    COUNT(*)-COUNT(a.submit_time) AS incomplete_cnt,
    COUNT(a.submit_time) AS complete_cnt,
    GROUP_CONCAT(DISTINCT CONCAT(date_format(a.start_time,'%Y-%m-%d'),':',b.tag) ORDER BY a.start_time ASC SEPARATOR ';') AS detail
FROM exam_record AS a
LEFT JOIN examination_info AS b ON a.exam_id = b.exam_id
WHERE 1=1
AND YEAR(a.start_time) = 2021
GROUP BY a.uid
HAVING COUNT(a.submit_time) >= 1 
AND (COUNT(*)-COUNT(a.submit_time)) BETWEEN 2 AND 4
ORDER BY incomplete_cnt DESC



发表于 2022-05-18 14:42:48 回复(1)
select uid,
sum(if(submit_time is null,1,0)) incomplete_cnt, 
count(submit_time) complete_cnt,
GROUP_CONCAT(distinct substr(start_time,1,10),':',tag separator';')
from exam_record er
join examination_info ei
on er.exam_id = ei.exam_id
where year(er.start_time)=2021
group by uid
having complete_cnt>=1 and incomplete_cnt<5 and incomplete_cnt>1
order by incomplete_cnt desc
发表于 2022-04-12 16:18:43 回复(1)
select uid,
(count(*)-count(submit_time))as incomplete_cnt,
count(submit_time)as complete_cnt,
group_concat(distinct concat(date(start_time),':',tag) order by start_time asc separator ';')as detail
#结合使用group_concat函数和concat函数
from exam_record as er left join examination_info as ei on er.exam_id=ei.exam_id 
where year(start_time)=2021
group by uid
having count(submit_time)>=1 #完成试卷作答数至少为1,及大于等于1。缺少=号,会报错
and (count(*)-count(submit_time))<5 
and (count(*)-count(submit_time))>1
order by incomplete_cnt desc;
供大家参考
发表于 2021-11-10 19:21:42 回复(2)
select e1.uid,sum(e1.submit_time is NULL) as incomplete_cnt,
sum(e1.submit_time is not null) as complete_cnt,
group_concat(distinct date_format(e1.start_time,'%Y-%m-%d'),':',e2.tag separator';')
from exam_record e1 left join examination_info e2
on e1.exam_id = e2.exam_id
where year(e1.start_time)=2021
group by e1.uid
having incomplete_cnt<5 and complete_cnt >=1 and incomplete_cnt>1
order by incomplete_cnt desc;

发表于 2022-11-16 15:41:55 回复(0)
SELECT t1.*,group_concat(distinct d separator ';') detil
FROM 
    (select uid,
         count(*)-count(submit_time) incomplete_cnt,
         count(submit_time) complete_cnt
    from exam_record 
    where year(start_time)=2021
    group by uid
        ) t1
join 
    (select uid, concat(date(start_time),':',tag) d
    from exam_record join examination_info
    using (exam_id)
    where year(start_time)=2021
        ) t2
using (uid)
WHERE complete_cnt>=1 and incomplete_cnt between 2 and 4
group by uid
order by incomplete_cnt desc

发表于 2022-03-23 21:38:15 回复(0)
发表于 2022-03-02 09:59:19 回复(0)
SELECT uid,sum(if(submit_time is null,1,0)) incomplete_cnt,
COUNT(submit_time) complete_cnt,
GROUP_CONCAT(DISTINCT CONCAT(STR_TO_DATE(start_time,'%Y-%m-%d'),':',tag) separator ';') detail
FROM exam_record e_r
JOIN examination_info e_i ON e_r.exam_id=e_i.exam_id
WHERE YEAR(start_time)=2021
GROUP BY uid
HAVING incomplete_cnt>1 AND incomplete_cnt<5 AND complete_cnt>=1
ORDER BY incomplete_cnt DESC;
count(score)和count(submit_time)应该是一样的吧,但是自测运行能通过,提交的时候1003就两个不一样,用score就通不过。
发表于 2022-02-23 13:10:58 回复(2)
1、连接两个表
2、通过where进行2021年份的筛选
3、使用group by 对uid进行分组
4、对分组后的数据计算,通过count和if结合来计算各个uid的完成数与未完成数
5、百度一下group_concat的用法,补充detail列内容,注意拼接
6、通过Having进行完成数与未完成数的条件筛选
7、完善排序等细节
select 
t1.uid as uid,
count(if(t1.submit_time is null,1,null)) as incomplete_cnt,
count(if(t1.submit_time is not null,1,null)) as complete_cnt,
group_concat(
	distinct concat(date_format(t1.start_time,'%Y-%m-%d'),':',t2.tag)
	order by t1.start_time
	separator ';'
) as detail
from exam_record t1
left join examination_info t2 on t1.exam_id = t2.exam_id
where year(start_time) = 2021
group by t1.uid
having complete_cnt >= 1 
and incomplete_cnt > 1
and incomplete_cnt < 5
order by incomplete_cnt desc



编辑于 2024-04-23 16:06:21 回复(0)
select
    uid,
    count(if(submit_time is null ,1,null)) as incomplete_cnt,
    count(submit_time) as complete_cnt ,
    replace(group_concat(distinct concat_ws(':',date_format(start_time,'%Y-%m-%d'),tag)),',',';' )as detail
from exam_record t1
join examination_info t2 on t1.exam_id = t2.exam_id
where year(start_time) = '2021'
group by uid
having complete_cnt > 1 and incomplete_cnt between 2 and 4
order by incomplete_cnt desc ;

编辑于 2024-04-01 20:36:28 回复(0)
select uid, count(start_time)-count(submit_time) as incomplete_cnt, count(submit_time) as complete_cnt, group_concat(distinct concat_ws(':',date(start_time),tag) separator ';') as detail
from exam_record as e inner join examination_info as ei on e.exam_id=ei.exam_id
where year(start_time) = '2021'
group by uid
having (count(start_time)-count(submit_time))>1 and count(submit_time)>=1 and (count(start_time)-count(submit_time))<5
order by incomplete_cnt desc;
发表于 2024-02-21 16:12:35 回复(0)

with a as (select uid,tag,date_format(start_time,'%Y-%m-%d') k1,date_format(submit_time,'%Y-%m') j1,
concat_ws(':',date_format(start_time,'%Y-%m-%d'),tag) ss
from exam_record er
join examination_info ei on er.exam_id = ei.exam_id
where start_time like "2021%")
select uid,count(k1)-count(j1) incomplete_cnt,count(j1) complete_cnt,
group_concat(distinct ss order by ss separator ';')
from a
group by uid
having incomplete_cnt > 1 and incomplete_cnt < 5 and  complete_cnt >= 1
order by incomplete_cnt desc
编辑于 2023-12-06 22:19:48 回复(0)

问题信息

难度:
385条回答 2002浏览

热门推荐

通过挑战的用户

查看代码
  • 二维码

    扫描二维码,关注牛客网

  • 二维码

    下载牛客APP,随时随地刷题