这谁能想到国庆我还在刷题,有一说一,写SQL题目挺好玩的

刷题心得:

写这种SQL题目,最最最为紧要的东西是要知道SQL的关键词的执行顺序,重要的事情说三遍:SQL的关键词的执行顺序!SQL的关键词的执行顺序!SQL的关键词的执行顺序!

在一个SELECT查询语句中,关键字的执行顺序如下:

  1. FROM:指定要查询的数据表或视图。
  2. JOIN:根据指定的连接条件,将多个表连接在一起。
  3. WHERE:对连接结果进行筛选,匹配满足条件的行。
  4. GROUP BY:根据指定的列对结果进行分组。
  5. HAVING:对分组后的结果进行筛选,匹配满足条件的分组。
  6. SELECT:选择要查询的列或表达式。
  7. DISTINCT:消除结果集中的重复行。
  8. ORDER BY:根据指定的列对结果进行排序。
  9. LIMIT:限制结果集的返回行数。

基础查询

查询结果限制返回行数

描述

题目:现在运营只需要查看前2个用户明细设备ID数据,请你从用户信息表 user_profile 中取出相应结果。

示例:

id device_id gender age university province
1 2138 male 21 北京大学 Beijing
2 3214 male 复旦大学 Shanghai
3 6543 female 20 北京大学 Beijing
4 2315 female 23 浙江大学 ZheJiang
5 5432 male 25 山东大学 Shandong

根据输入,你的查询应返回以下结果:

device_id
2138
3214

select device_id from user_profile limit 2

将查询后的列重新命名

描述

题目:现在你需要查看前2个用户明细设备ID数据, 并将列名改为 ‘user_infos_example’,,请你从用户信息表取出相应结果。

示例:user_profile

id device_id gender age university province
1 2138 male 21 北京大学 Beijing
2 3214 male 复旦大学 Shanghai
3 6543 female 20 北京大学 Beijing
4 2315 female 23 浙江大学 ZheJiang
5 5432 male 25 山东大学 Shandong

根据示例,你的查询应返回以下结果:

user_infos_example
2138
3214

select device_id as user_infos_example from user_profile limit 2

条件查询

Where in 和Not in

描述

题目:现在运营想要找到学校为北大、复旦和山大的同学进行调研,请你取出相关数据。

示例:user_profile

id device_id gender age university gpa
1 2138 male 21 北京大学 3.4
2 3214 male 复旦大学 4.0
3 6543 female 20 北京大学 3.2
4 2315 female 23 浙江大学 3.6
5 5432 male 25 山东大学 3.8

根据输入,你的查询应返回以下结果:

device_id gender age university gpa
2138 male 21 北京大学 3.4
3214 male 复旦大学 4.0
6543 female 20 北京大学 3.2
5432 male 25 山东大学 3.8

select device_id,gender,age,university,gpa from user_profile where university in(‘北京大学’,’复旦大学’,’山东大学’)

查看学校名称中含北京的用户

描述

题目:现在运营想查看所有大学中带有北京的用户的信息,请你取出相应数据。

示例:用户信息表:user_profile

id device_id gender age university gpa
1 2138 male 21 北京大学 3.4
2 3214 male 复旦大学 4.0
3 6543 female 20 北京大学 3.2
4 2315 female 23 浙江大学 3.6
5 5432 male 25 山东大学 3.8
6 2131 male 28 北京师范大学 3.3

根据示例,你的查询应返回如下结果:

device_id age university
2138 21 北京大学
6543 20 北京大学
2131 28 北京师范大学

select device_id,age,university from user_profile where university like ‘北京%’

高级查询

分组过滤练习题

描述

题目:现在运营想查看每个学校用户的平均发贴和回帖情况,寻找低活跃度学校进行重点运营,请取出平均发贴数低于5的学校或平均回帖数小于20的学校。

示例:user_profile

id device_id gender age university gpa active_days_within_30 question_cnt answer_cnt
1 2138 male 21 北京大学 3.4 7 2 12
2 3214 male 复旦大学 4.0 15 5 25
3 6543 female 20 北京大学 3.2 12 3 30
4 2315 female 23 浙江大学 3.6 5 1 2
5 5432 male 25 山东大学 3.8 20 15 70
6 2131 male 28 山东大学 3.3 15 7 13
7 4321 female 26 复旦大学 3.6 9 6 52

第一行表示:id为1的用户的常用信息为使用的设备id为2138,性别为男,年龄21岁,北京大学,gpa为3.4在过去的30天里面活跃了7天,发帖数量为2,回答数量为12
。。。
最后一行表示:id为7的用户的常用信息为使用的设备id为4321,性别为男,年龄26岁,复旦大学,gpa为3.6在过去的30天里面活跃了9天,发帖数量为6,回答数量为52

根据示例,你的查询应返回以下结果,请你保留3位小数(系统后台也会自动校正),3位之后四舍五入:

university avg_question_cnt avg_answer_cnt
北京大学 2.5000 21.000
浙江大学 1.000 2.000

解释: 平均发贴数低于5的学校或平均回帖数小于20的学校有2个

属于北京大学的用户的平均发帖量为2.500,平均回答数量为21.000

属于浙江大学的用户的平均发帖量为1.000,平均回答数量为2.000

1
select university,avg(question_cnt) as avg_question_cnt,avg(answer_cnt) as avg_answer_cnt from user_profile group by university having avg(question_cnt) < 5 or avg(answer_cnt) < 20

多表查询

浙江大学用户题目回答情况

描述

题目:现在运营想要查看所有来自浙江大学的用户题目回答明细情况,请你取出相应数据

示例 :question_practice_detail

id device_id question_id result
1 2138 111 wrong
2 3214 112 wrong
3 3214 113 wrong
4 6543 114 right
5 2315 115 right
6 2315 116 right
7 2315 117 wrong

第一行表示:id为1的用户的常用信息为使用的设备id为2138,在question_id为111的题目上,回答错误

….

最后一行表示:id为7的用户的常用信息为使用的设备id为2135,在question_id为117的题目上,回答错误

示例:user_profile

id device_id gender age university gpa active_days_within_30 question_cnt answer_cnt
1 2138 male 21 北京大学 3.4 7 2 12
2 3214 male 复旦大学 4.0 15 5 25
3 6543 female 20 北京大学 3.2 12 3 30
4 2315 female 23 浙江大学 3.6 5 1 2
5 5432 male 25 山东大学 3.8 20 15 70
6 2131 male 28 山东大学 3.3 15 7 13
7 4321 female 26 复旦大学 3.6 9 6 52

第一行表示:id为1的用户的常用信息为使用的设备id为2138,性别为男,年龄21岁,北京大学,gpa为3.4在过去的30天里面活跃了7天,发帖数量为2,回答数量为12
。。。
最后一行表示:id为7的用户的常用信息为使用的设备id为4321,性别为男,年龄26岁,复旦大学,gpa为3.6在过去的30天里面活跃了9天,发帖数量为6,回答数量为52

根据示例,你的查询应返回以下结果,查询结果根据question_id升序排序:

img

解释:

根据题目的数据只有1个浙江大学的用户,那么把浙江大学这个用户所有答题数据查询出来就行

1
select A.device_id,A.question_id,result from question_practice_detail as A join user_profile as B on A.device_id = B.device_id where university = '浙江大学'

2023-10-04

统计每个学校各难度的用户平均刷题数

描述

题目:运营想要计算一些参加了答题的不同学校、不同难度的用户平均答题量,请你写SQL取出相应数据

用户信息表:user_profile

id device_id gender age university gpa active_days_within_30 question_cnt answer_cnt
1 2138 male 21 北京大学 3.4 7 2 12
2 3214 male NULL 复旦大学 4 15 5 25
3 6543 female 20 北京大学 3.2 12 3 30
4 2315 female 23 浙江大学 3.6 5 1 2
5 5432 male 25 山东大学 3.8 20 15 70
6 2131 male 28 山东大学 3.3 15 7 13
7 4321 male 28 复旦大学 3.6 9 6 52

第一行表示:id为1的用户的常用信息为使用的设备id为2138,性别为男,年龄21岁,北京大学,gpa为3.4,在过去的30天里面活跃了7天,发帖数量为2,回答数量为12

最后一行表示:id为7的用户的常用信息为使用的设备id为4321,性别为男,年龄28岁,复旦大学,gpa为3.6,在过去的30天里面活跃了9天,发帖数量为6,回答数量为52

题库练习明细表:question_practice_detail

id device_id question_id result
1 2138 111 wrong
2 3214 112 wrong
3 3214 113 wrong
4 6534 111 right
5 2315 115 right
6 2315 116 right
7 2315 117 wrong
8 5432 117 wrong
9 5432 112 wrong
10 2131 113 right
11 5432 113 wrong
12 2315 115 right
13 2315 116 right
14 2315 117 wrong
15 5432 117 wrong
16 5432 112 wrong
17 2131 113 right
18 5432 113 wrong
19 2315 117 wrong
20 5432 117 wrong
21 5432 112 wrong
22 2131 113 right
23 5432 113 wrong

第一行表示:id为1的用户的常用信息为使用的设备id为2138,在question_id为111的题目上,回答错误

……

最后一行表示:id为23的用户的常用信息为使用的设备id为5432,在question_id为113的题目上,回答错误

表:question_detail

id question_id difficult_level
1 111 hard
2 112 medium
3 113 easy
4 115 easy
5 116 medium
6 117 easy

第一行表示: 题目id为111的难度为hard

….

第一行表示: 题目id为117的难度为easy

请你写一个SQL查询,计算不同学校、不同难度的用户平均答题量,根据示例,你的查询应返回以下结果(结果在小数点位数保留4位,4位之后四舍五入):

university difficult_level avg_answer_cnt
北京大学 hard 1.0000
复旦大学 easy 1.0000
复旦大学 medium 1.0000
山东大学 easy 4.5000
山东大学 medium 3.0000
浙江大学 easy 5.0000
浙江大学 medium 2.0000

解释:

第一行:北京大学有设备id为2138,6543这2个用户,这2个用户在question_practice_detail表下都只有一条答题记录,且答题题目是111,从question_detail可以知道这个题目是hard,故 北京大学的用户答题为hard的题目平均答题为2/2=1.0000

第二行,第三行:复旦大学有设备id为3214,4321这2个用户,但是在question_practice_detail表只有1个用户(device_id=3214有答题,device_id=4321没有答题,不计入后续计算)有2条答题记录,且答题题目是112,113各1个,从question_detail可以知道题目难度分别是medium和easy,故 复旦大学的用户答题为easy, medium的题目平均答题量都为1(easy=1或medium=1) /1 (device_id=3214)=1.0000

第四行,第五行:山东大学有设备id为5432和2131这2个用户,这2个用户总共在question_practice_detail表下有12条答题记录,且答题题目是112,113,117,且数目分别为3,6,3,从question_detail可以知道题目难度分别为medium,easy,easy,所以,easy共有9个,故easy的题目平均答题量= 9(easy=9)/2 (device_id=3214 or device_id=5432) =4.5000,medium共有3个,medium的答题只有device_id=5432的用户,故medium的题目平均答题量= 3(medium=9)/1 ( device_id=5432) =3.0000

…..

1
2
3
4
5
6
7
8
9
10
11
select
university,
difficult_level,
count(B.question_id) / count(distinct A.device_id) as avg_answer_cnt
from
user_profile as A
join question_practice_detail as B on A.device_id = B.device_id
join question_detail as C on B.question_id = C.question_id
group by
university,
difficult_level

日期函数

计算用户的平均次日留存率

描述

题目:现在运营想要查看用户在某天刷题后第二天还会再来刷题的平均概率。请你取出相应数据。

示例:question_practice_detail

id device_id quest_id result date
1 2138 111 wrong 2021-05-03
2 3214 112 wrong 2021-05-09
3 3214 113 wrong 2021-06-15
4 6543 111 right 2021-08-13
5 2315 115 right 2021-08-13
6 2315 116 right 2021-08-14
7 2315 117 wrong 2021-08-15
……

根据示例,你的查询应返回以下结果:

avg_ret
0.3000
1
select qpd.date as date1 from question_practice_detail as qpd left join question_practice_detail as qpd1 on qpd.device_id = qpd1.device_id and date_add(qpd.date, interval 1 day) = qpd1.date

这个题目最大的收获就是,当值为null的时候,count函数是不会把这个值算进去的

文本函数

统计每种性别的人数

描述

题目:现在运营举办了一场比赛,收到了一些参赛申请,表数据记录形式如下所示,现在运营想要统计每个性别的用户分别有多少参赛者,请取出相应结果

示例:user_submit

device_id profile blog_url
2138 180cm,75kg,27,male http:/url/bigboy777
3214 165cm,45kg,26,female http:/url/kittycc
6543 178cm,65kg,25,male http:/url/tiger
4321 171cm,55kg,23,female http:/url/uhksd
2131 168cm,45kg,22,female http:/urlsydney

根据示例,你的查询应返回以下结果:

gender number
male 2
female 3

第一次尝试写的:

1
select case when profile.contains("male") then "male" when profile.contains("female") then "female" end as gender,count(*) as number from user_submit group by gender

正解是:

1
select substring_index(profile,',',-1) as gender,count(*) as number from user_submit group by gender

截取出年龄

描述

题目:现在运营举办了一场比赛,收到了一些参赛申请,表数据记录形式如下所示,现在运营想要统计每个年龄的用户分别有多少参赛者,请取出相应结果

示例:user_submit

device_id profile blog_url
2138 180cm,75kg,27,male http:/ur/bigboy777
3214 165cm,45kg,26,female http:/url/kittycc
6543 178cm,65kg,25,male http:/url/tiger
4321 171cm,55kg,23,female http:/url/uhksd
2131 168cm,45kg,22,female http:/url/sydney

根据示例,你的查询应返回以下结果:

age number
27 1
26 1
25 1
23 1
22 1

第一次尝试写的:

1
select substring_index(profile,',',-2) as age, count(*) as number from user_submit group by age

正解是:

1
select substring_index(substring_index(profile,',',3),',',-1) as age, count(*) as number from user_submit group by age

窗口函数

找出每个学校GPA最低的同学

描述

题目:现在运营想要找到每个学校gpa最低的同学来做调研,请你取出每个学校的最低gpa。

示例:user_profile

id device_id gender age university gpa active_days_within_30 question_cnt answer_cnt
1 2138 male 21 北京大学 3.4 7 2 12
2 3214 male 复旦大学 4 15 5 25
3 6543 female 20 北京大学 3.2 12 3 30
4 2315 female 23 浙江大学 3.6 5 1 2
5 5432 male 25 山东大学 3.8 20 15 70
6 2131 male 28 山东大学 3.3 15 7 13
7 4321 female 26 复旦大学 3.6 9 6 52

根据示例,你的查询结果应参考以下格式,输出结果按university升序排序:

device_id university gpa
6543 北京大学 3.2000
4321 复旦大学 3.6000
2131 山东大学 3.3000
2315 浙江大学 3.6000

我原来写的:

1
select device_id,university,round(min(gpa),4) as min from user_profile group by university

这种写法,开始我以为能通过min()函数就能得到结果,但是因为学校与学生是一对多的关系,如果仅用min求出gpa最低的学生,查询结果中的id与学生不一定是对应的关系

正解:

1
select device_id,university,gpa from (select device_id,university,gpa,RANK() over (PARTITION BY university ORDER BY gpa) as rk from user_profile) as rks where rks.rk = 1

综合练习

统计复旦用户8月练题情况

描述

题目: 现在运营想要了解复旦大学的每个用户在8月份练习的总题目数和回答正确的题目数情况,请取出相应明细数据,对于在8月份没有练习过的用户,答题数结果返回0.

示例:用户信息表user_profile

id device_id gender age university gpa active_days_within_30
1 2138 male 21 北京大学 3.4 7
2 3214 male 复旦大学 4.0 15
3 6543 female 20 北京大学 3.2 12
4 2315 female 23 浙江大学 3.6 5
5 5432 male 25 山东大学 3.8 20
6 2131 male 28 山东大学 3.3 15
7 4321 female 26 复旦大学 3.6 9

示例:question_practice_detail

id device_id question_id result date
1 2138 111 wrong 2021-05-03
2 3214 112 wrong 2021-05-09
3 3214 113 wrong 2021-06-15
4 6543 111 right 2021-08-13
5 2315 115 right 2021-08-13
6 2315 116 right 2021-08-14
7 2315 117 wrong 2021-08-15
……

根据示例,你的查询应返回以下结果:

device_id university question_cnt right_question_cnt
3214 复旦大学 3 0
4321 复旦大学 0 0

这道题花了30分钟左右,A了,爽的很

1
select up.device_id,university,count(question_id) as question_cnt,sum(if(result="right",1,0)) as right_question_cnt from user_profile as up left join (select device_id,question_id,result from question_practice_detail where DATE_FORMAT(date, "%Y-%m") = '2021-08') as qpd on up.device_id = qpd.device_id where university = '复旦大学' group by up.device_id

21年8月份练题总数

描述

题目: 现在运营想要了解2021年8月份所有练习过题目的总用户数和练习过题目的总次数,请取出相应结果

示例:question_practice_detail

id device_id question_id result date
1 2138 111 wrong 2021-05-03
2 3214 112 wrong 2021-05-09
3 3214 113 wrong 2021-06-15
4 6543 111 right 2021-08-13
5 2315 115 right 2021-08-13
6 2315 116 right 2021-08-14
7 2315 117 wrong 2021-08-15
……

根据的示例,你的查询应返回以下结果:

did_cnt question_cnt
3 12
  1. 筛选: where DATE_FORMAT(date,’%Y-%m’) = ‘2021-08’
  2. 不同的device_id个数
  3. question_id的总数

我原来的写法:

1
select count(*) as did_cnt,sum(question_cnt) from (select count(device_id) as did_cnt, count(question_id) as question_cnt from question_practice_detail as qpd where DATE_FORMAT(qpd.date, '%Y-%m') = '2021-08' group by device_id)

这么写确实能过哈哈哈,但是有点太low了

应该这样写

1
select count(distinct device_id) as did_cnt, count(question_id) as question_cnt from question_practice_detail as qpd where DATE_FORMAT(qpd.date, '%Y-%m') = '2021-08'