首页 > 试题广场 >

每个题目和每份试卷被作答的人数和次数

[编程题]每个题目和每份试卷被作答的人数和次数
  • 热度指数:86927 时间限制: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-09-01 09:01:01
2021-09-01 09:41:01 81
2 1002
9002
2021-09-01 12:01:01
2021-09-01 12:31:01 70
3 1002
9001
2021-09-01 19:01:01
2021-09-01 19:40:01 80
4 1002
9002
2021-09-01 12:01:01
2021-09-01 12:31:01 70
5 1004
9001
2021-09-01 19:01:01
2021-09-01 19:40:01
85
6 1002
9002
2021-09-01 12:01:01
(NULL) (NULL)

题目练习表practice_record(uid用户ID, question_id题目ID, submit_time提交时间, score得分):
id uid question_id submit_time score
1 1001 8001
2021-08-02 11:41:01 60
2 1002
8001
2021-09-02 19:30:01 50
3 1002
8001
2021-09-02 19:20:01 70
4 1002
8002
2021-09-02 19:38:01 70
5 1003
8001
2021-08-02 19:38:01
70
6 1003
8001
2021-08-02 19:48:01
90
7 1003
8002
2021-08-01 19:38:01 80

请统计每个题目和每份试卷被作答的人数和次数,分别按照"试卷"和"题目"的uv & pv降序显示,示例数据结果输出如下:
tid uv pv
9001 3 3
9002 1 3
8001
3 5
8002 2 2
解释:“试卷”有3人共练习3次试卷9001,1人作答3次9002;“刷题”有3人刷5次8001,有2人刷2次8002
示例1

输入

drop table if exists practice_record;
CREATE TABLE  practice_record (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    uid int NOT NULL COMMENT '用户ID',
    question_id int NOT NULL COMMENT '题目ID',
    submit_time datetime COMMENT '提交时间',
    score tinyint 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 practice_record(uid,question_id,submit_time,score) VALUES
(1001, 8001, '2021-08-02 11:41:01', 60),
(1002, 8001, '2021-09-02 19:30:01', 50),
(1002, 8001, '2021-09-02 19:20:01', 70),
(1002, 8002, '2021-09-02 19:38:01', 70),
(1003, 8001, '2021-08-02 19:38:01', 70),
(1003, 8001, '2021-08-02 19:48:01', 90),
(1003, 8002, '2021-08-01 19:38:01', 80);

INSERT INTO exam_record(uid,exam_id,start_time,submit_time,score) VALUES
(1001, 9001, '2021-09-01 09:01:01', '2021-09-01 09:41:01', 81),
(1002, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 70),
(1002, 9001, '2021-09-01 19:01:01', '2021-09-01 19:40:01', 80),
(1002, 9002, '2021-09-01 12:01:01', '2021-09-01 12:31:01', 70),
(1004, 9001, '2021-09-01 19:01:01', '2021-09-01 19:40:01', 85),
(1002, 9002, '2021-09-01 12:01:01', null, null);

输出

9001|3|3
9002|1|3
8001|3|5
8002|2|2
解题的关键是使用union后的排序问题

首先明确,union可以使用任何selcet语句,但order by子句只能在最后一次使用

所以,如果想要对未union前两个sql语句的查询结果进行排序,分别单独排序需要的数据,查出以后再使用union连接
select * from
( select * from t1  order by 字段 )t1 -- 一定要对表重新命名,否则报错 
union select * from
( select * from t2  order by 字段 )t2

综上,本题代码如下

select * from 
(SELECT exam_id tid,count(DISTINCT uid) uv,count(uid) pv from exam_record
group by exam_id
order by uv desc,pv desc)a
UNION ALL
SELECT * FROM
(SELECT question_id tid,count(DISTINCT uid) uv,count(uid) pv from practice_record
GROUP BY question_id
order by uv desc,pv desc)b
;

发表于 2021-10-22 11:40:52 回复(7)

【分类】:合并查询

分析思路

难点:
1.MySQL union 和 order by 同时使用需要注意的问题

扩展:

前往查看:MySQL union 和 order by 一起使用需要注意的问题

错误的情况

(1)使用 union 和 多个order by 不加括号 报错

(2)order by 在 union 连接的子句不起作用,但是在子句的子句中起作用

解决上述问题的两种方法

(1)先使用 union 后使用order by

(2)order by 在 union 连接的子句的子句中使用

常见的错误写法

(1)使用 union 和 多个order by 不加括号 【报错】

select 
    exam_id as tid,
    count(distinct uid) as uv,
    count(uid) as pv
from exam_record a
group by exam_id
order by uv desc, pv desc
union
select 
    question_id as tid,
    count(distinct uid) as uv,
    count(uid) as pv
from practice_record b
group by question_id
order by uv desc, pv desc

执行出错

程序异常退出, 请检查代码"是否有数组越界等异常"或者"是否有语法错误"
SQL_ERROR_INFO: "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'union all\n\nselect \n question_id as tid,\n count(distinct uid) as uv,\n co' at line 11"

这是因为union在没有括号的情况下只能有一个order by。为什么只能有一个order by 呢?

既然不加括号出错,那我就加上括号使用2个order by !

(2)order by 在 union 连接的子句不起作用,但是在子句的子句中起作用

(select 
    exam_id as tid,
    count(distinct uid) as uv,
    count(uid) as pv
from exam_record a
group by exam_id
order by uv desc, pv desc)
union
(select 
    question_id as tid,
    count(distinct uid) as uv,
    count(uid) as pv
from practice_record b
group by question_id
order by uv desc, pv desc)

结果发现这样写order by在每个子表中不起作用!所以这种方法也不对。但是 union 可以在子句的子句中起作用,写成下面这样:

方法一:

#正确代码
select * from 
(
select 
    exam_id as tid,
    count(distinct uid) as uv,
    count(uid) as pv
from exam_record a
group by exam_id
order by uv desc, pv desc
) a
union
select * from 
(
select 
    question_id as tid,
    count(distinct uid) as uv,
    count(uid) as pv
from practice_record b
group by question_id
order by uv desc, pv desc
) attr

那我是不是可以union两个子句之后再使用order by ,但是这个排序要对2个表分别进行降序,就需要写成下面这样:

方法二:

使用函数

left(str,length) 函数: str左边开始的长度为 length 的子字符串,在本例中为‘9’和‘8’
解释:试卷编号以‘9’开头、题目编号以‘8’开头,对编号进行降序就是对"试卷"和"题目"分别进行排序

(
    #每份试卷被作答的人数和次数
    select
        exam_id as tid,
        count(distinct uid) as uv,
        count(*) as pv
from exam_record
group by exam_id
)
union
(
    #每个题目被作答的人数和次数
    select
        question_id as tid,
        count(distinct uid) as uv,
        count(*) as pv
from practice_record
group by question_id
)
#分别按照"试卷"和"题目"的uv & pv降序显示
order by left(tid,1) desc,uv desc,pv desc
编辑于 2022-11-09 12:30:43 回复(7)
(select exam_id as tid,count(distinct uid) as uv,count(*) as pv
from exam_record
group by exam_id)
union
(select question_id as tid,count(distinct uid),count(*)
from practice_record
group by question_id)
order by left(tid,1) desc,uv desc,pv desc

发表于 2021-10-21 18:10:04 回复(8)
# 不用动脑排序的傻瓜方法
with t1 as
(select exam_id as tid, 
count(distinct uid)as uv, 
count(distinct id)as pv from exam_record
group by exam_id
order by uv desc, pv desc),
t2 as
(select question_id as tid, 
count(distinct uid)as uv, 
count(distinct id)as pv from practice_record
where score is not null
group by question_id
order by uv desc, pv desc)

select * from t1 
union all 
select * from t2 
发表于 2021-12-28 02:33:26 回复(0)
select t.tid ,
count(distinct uid) as uv,
count(*)
from (
select uid,exam_id as tid from exam_record
union 
select uid,question_id from practice_record)t
group by t.tid 

由于这道题要求对 试卷和练习的结果分别排序,所以上方的写法就没有办法实现了。

with t1 as 

(select  exam_id as tid , count(distinct uid) as uv ,
count(*) as pv
from exam_record
group by tid order by uv desc,pv desc),
t2 as 
(select  question_id as tid , count(distinct uid) as uv ,
count(*) as pv
from practice_record
group by tid order by uv desc ,pv desc)

select * from t1 
union 
select * from t2

由于union 的排序最能跟在最后的语句中,即只出现一次。

所以用临时表的方式,或者在每个union 外面再加一层查询都是可以的。

这题的有点刁钻了。

发表于 2022-08-19 16:51:46 回复(0)
在排序那一行的代码后面添加上  limit 9999 就行了
如下所示:
order by uv desc, pv desc limit 9999
因为order by可以存在 union的字句里面,但是它的功能不会生效,所以需要修改一下
发表于 2022-03-12 16:41:45 回复(1)
order by LEFT(tid,1) DESC, uv desc, pv desc   这个语句什么含义呀 大佬们
发表于 2021-11-30 21:42:31 回复(3)
这道题的“难点”在于最后的排序
1.可以选择每组分别排序,但注意要给每组定义变量
代码:
select * from
(
select exam_id tid,count(distinct uid) uv,count(uid) pv from exam_record
group by tid
order by uv desc,pv desc) a
union
select * from
(
select question_id tid,count(distinct uid) uv,count(uid) pv from practice_record
group by tid
order by uv desc,pv desc
) b
2.可以选择最后排序,添加排序的时候注意限制分组字段
代码:
SELECT exam_id as tid, 
  count(distinct uid) as uv,
  count(uid) as pv
from exam_record
group by exam_id
union ALL
SELECT question_id as tid,
  count(distinct uid) as uv,
  count(uid) as pv
from practice_record
group by question_id
order by LEFT(tid,2) DESC,uv DESC,pv DESC;



发表于 2022-05-07 10:31:21 回复(0)
select
exam_id tid
,count(distinct uid) uv
,count(*) pv
from exam_record
group by tid
union all
select
question_id tid
,count(distinct uid) uv
,count(*) pv
from practice_record
group by tid
order by left(tid,1) desc,uv desc,pv desc
#分组排序的时候只需要把分组依据也加到order by

发表于 2021-12-26 19:09:37 回复(2)
很神奇!尝试了两种方法:
# # 每个题目: 可以是exam_id, 可以使question_id]
# 被作答:start_time : submit time
# 分别按照"试卷"和"题目"的uv & pv降序显示

# 方法一:

SELECT er.*
FROM
(SELECT 
    exam_id AS tid,
    COUNT(DISTINCT uid) AS uv,
    COUNT(start_time) AS pv
FROM exam_record 
GROUP BY tid
ORDER BY uv DESC, pv DESC) er

UNION ALL

SELECT pr.*
FROM
(SELECT 
    question_id AS tid,
    COUNT(DISTINCT uid) AS uv,
    COUNT(submit_time) AS pv
FROM practice_record 
GROUP BY tid
ORDER BY uv DESC, pv DESC) pr

# The ORDER BY clause cannot be used within a UNION clause. To sort the results, you need to use two separate SELECT statements and nest them

# 方法二:

WITH er AS (
    SELECT 
    exam_id AS tid,
    COUNT(DISTINCT uid) AS uv,
    COUNT(start_time) AS pv
FROM exam_record 
GROUP BY tid
ORDER BY uv DESC, pv DESC
),
    pr AS (
    SELECT 
    question_id AS tid,
    COUNT(DISTINCT uid) AS uv,
    COUNT(submit_time) AS pv
FROM practice_record 
GROUP BY tid
ORDER BY uv DESC, pv DESC) 

SELECT er.* 
FROM er 
UNION ALL 
SELECT pr.*
FROM pr

# 感觉方法二更直观清楚一些。




发表于 2023-02-02 07:34:30 回复(0)
这种排序方法我还没见过……
order by left(tid,1desc 根据tid 左边第一个数降序排列
发表于 2022-10-27 17:26:14 回复(0)
为什么这么写,并没有进行降序排序
发表于 2021-11-19 15:24:00 回复(6)
SELECT a.tid,a.uv,a.pv
FROM(    
    SELECT exam_id as tid,count(distinct uid) as uv,count(id) as pv
    FROM exam_record
    GROUP BY exam_id
    UNION ALL
    SELECT question_id as tid,count(distinct uid) as uv,count(id) as pv
    FROM practice_record
    GROUP BY question_id) a
ORDER BY left(a.tid,1) desc,a.uv desc,a.pv desc
每次排序都能搞出很多事
发表于 2021-10-26 10:55:45 回复(2)
select exam_id tid,count(distinct uid) UV,count(*) PV
from exam_record
group by tid 
union all
select question_id tid,count(distinct uid) UV,count(*) PV
from practice_record 
group by tid
order by left(tid,1) desc,UV desc,PV desc
2注意题目要求的排序:分别按照"试卷"和"题目"的uv & pv降序显示
select *
from(
select exam_id tid,count(distinct uid) uv,count(1) pv
from exam_record
group by 1
order by 2 desc,3 desc
) a
union all
select *
from(
select question_id tid,count(distinct uid) uv,count(1) pv
from practice_record 
group by 1
order by 2 desc,3 desc
) b
3.用with a as () , b as ()创建中间表
with a as(
select exam_id tid,count(distinct uid) uv,count(1) pv
from exam_record
group by 1
order by 2 desc,3 desc
), 
b as(
select question_id tid,count(distinct uid) uv,count(1) pv
from practice_record 
group by 1
order by 2 desc,3 desc
)
select *
from a
union all
select *
from b

编辑于 2023-12-09 18:10:55 回复(0)
# 请统计每个题目和每份试卷被作答的人数和次数,分别按照"试卷"和"题目"的uv & pv降序显示,示例数据结果输出如下:

-- 注意最后输出结果排序
select tid,uv,pv
from 
(
select exam_id as tid,count(distinct uid) uv,count(uid) pv from exam_record group by exam_id 
union all 
select question_id as tid,count(distinct uid) uv,count(uid) pv from practice_record group by question_id 
) tt
order by substr(tid,1,1) desc,  pv desc

发表于 2023-09-04 16:39:14 回复(0)
通过添加常数字段exam_question 从而能够使用order by exam 和 question进行排序
select tid, uv, pv
from (SELECT exam_id as tid,
count(distinct uid) as uv,
count(start_time) as pv,
1 as exam_question
from exam_record
group by tid
union all 
select question_id as tid,
count(distinct uid) as uv,
count(submit_time) as pv,
0 as exam_question
from practice_record
group by tid) e_q_all
order by exam_question desc, uv desc, pv desc;


发表于 2023-03-08 15:39:20 回复(0)
考试和练习的统计结果进行union all即可。

with stat_exam as(
    select exam_id,
    count(distinct uid) as uv,
    count(uid) as pv 
    from exam_record
    group by exam_id
    order by uv desc,pv desc
)
,
stat_practice as(
    select question_id,
    count(distinct uid) as uv,
    count(uid) as pv 
    from practice_record
    group by question_id
    order by uv desc,pv desc
)
select * from stat_exam
union all
select * from stat_practice


发表于 2023-03-07 19:38:58 回复(0)
(
  select
    exam_id as tid,
    count(distinct uid) as uv,
    count(id) as pv
  from
    exam_record
  group by
    exam_id
  order by
    uv desc,
    pv desc
  limit
    9999
)
union all
(
  select
    question_id as tid,
    count(distinct uid) as uv,
    count(id) as pv
  from
    practice_record
  group by
    question_id
  order by
    uv desc,
    pv desc
  limit
    9999
)

发表于 2022-09-07 17:37:31 回复(1)
with a as (
select 
exam_id,
count(distinct uid) as uv,
count(uid) as pv
from exam_record 
group by exam_id
order by uv desc,pv desc),
b as (
select 
question_id,
count(distinct uid) as uv,
count(uid) as pv
from practice_record
group by question_id
order by uv desc,pv desc)


select * from a 
union all
select * from b

编辑于 2024-04-04 15:34:39 回复(0)
要点:
1.对两个表分别筛选信息排序后使用union 或 union all合并即可。
2.易错点:①分别排序再union,报错!②union的排序的两部分都加上括号,不报错,但是排序不起作用,即order by 在 union 连接的子句不起作用 ③order by在union连接的子句的子句中起作用。正确代码如下:
select *
from  (select exam_id as tid, count(distinct uid) as uv, count(uid) as pv
from exam_record
group by exam_id
order by uv desc, pv desc) as a

union

select *
from  (select question_id as tid, count(distinct uid) as uv, count(uid) as pv
from practice_record
group by question_id
order by uv desc, pv desc) as b;

编辑于 2024-03-25 20:01:03 回复(0)

问题信息

难度:
137条回答 967浏览

热门推荐

通过挑战的用户

查看代码
  • 二维码

    扫描二维码,关注牛客网

  • 二维码

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