50道SQL练习题及答案
2019-06-07 本文已影响47人
一叶云秋
网上流传这这样的50道练习题,以下是我的解法,仅供各位联系和参考
数据表介绍
--1.学生表
Student(SId,Sname,Sage,Ssex)
--SId 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别
--2.课程表
Course(CId,Cname,TId)
--CId 课程编号,Cname 课程名称,TId 教师编号
--3.教师表
Teacher(TId,Tname)
--TId 教师编号,Tname 教师姓名
--4.成绩表
SC(SId,CId,score)
--SId 学生编号,CId 课程编号,score 分数
学生表 Student
create table Student(SId varchar(10),Sname varchar(10),Sage datetime,Ssex varchar(10));
insert into Student values('01' , '赵雷' , '1990-01-01' , '男');
insert into Student values('02' , '钱电' , '1990-12-21' , '男');
insert into Student values('03' , '孙风' , '1990-12-20' , '男');
insert into Student values('04' , '李云' , '1990-12-06' , '男');
insert into Student values('05' , '周梅' , '1991-12-01' , '女');
insert into Student values('06' , '吴兰' , '1992-01-01' , '女');
insert into Student values('07' , '郑竹' , '1989-01-01' , '女');
insert into Student values('09' , '张三' , '2017-12-20' , '女');
insert into Student values('10' , '李四' , '2017-12-25' , '女');
insert into Student values('11' , '李四' , '2012-06-06' , '女');
insert into Student values('12' , '赵六' , '2013-06-13' , '女');
insert into Student values('13' , '孙七' , '2014-06-01' , '女');
科目表 Course
create table Course(CId varchar(10),Cname nvarchar(10),TId varchar(10));
insert into Course values('01' , '语文' , '02');
insert into Course values('02' , '数学' , '01');
insert into Course values('03' , '英语' , '03');
教师表 Teacher
create table Teacher(TId varchar(10),Tname varchar(10));
insert into Teacher values('01' , '张三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');
成绩表 SC
create table SC(SId varchar(10),CId varchar(10),score decimal(18,1));
insert into SC values('01' , '01' , 80);
insert into SC values('01' , '02' , 90);
insert into SC values('01' , '03' , 99);
insert into SC values('02' , '01' , 70);
insert into SC values('02' , '02' , 60);
insert into SC values('02' , '03' , 80);
insert into SC values('03' , '01' , 80);
insert into SC values('03' , '02' , 80);
insert into SC values('03' , '03' , 80);
insert into SC values('04' , '01' , 50);
insert into SC values('04' , '02' , 30);
insert into SC values('04' , '03' , 20);
insert into SC values('05' , '01' , 76);
insert into SC values('05' , '02' , 87);
insert into SC values('06' , '01' , 31);
insert into SC values('06' , '03' , 34);
insert into SC values('07' , '02' , 89);
insert into SC values('07' , '03' , 98);
练习题目
1. 查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数
join课程1成绩表和课程2成绩表,然后对该表进行筛选
SELECT
c.SId,
d.Sname,
d.Sage,
d.Ssex,
c.S_01,
c.S_02
FROM
(
SELECT
a.SId,
a.score AS S_01,
b.score AS S_02
FROM
(
SELECT
*
FROM
50exercises.sc
WHERE
CId = 01
) AS a
JOIN (
SELECT
*
FROM
50exercises.sc
WHERE
CId = 02
) AS b ON a.SId = b.SId
WHERE
a.score > b.score
) AS c
JOIN 50exercises.student AS d ON c.SId = d.SId
1.1. 查询同时存在" 01 "课程和" 02 "课程的情况
解题思路 join课程1和课程2的两张表
SELECT
a.SId,
a.score AS S_01,
b.score AS S_02
FROM
(
SELECT
*
FROM
50exercises.sc
WHERE
CId = 01
) AS a
JOIN (
SELECT
*
FROM
50exercises.sc
WHERE
CId = 02
) AS b ON a.SId = b.SId
1.2. 查询存在" 01 "课程但可能不存在" 02 "课程的情况(不存在时显示为 null )
left join课程1和课程2
SELECT
a.SId,
a.score AS S_01,
b.score AS S_02
FROM
(
SELECT
*
FROM
50exercises.sc
WHERE
CId = 01
) AS a
left JOIN (
SELECT
*
FROM
50exercises.sc
WHERE
CId = 02
) AS b ON a.SId = b.SId
1.3. 查询不存在" 01 "课程但存在" 02 "课程的情况
与1.2思路相似,反之即可
SELECT
a.SId,
a.score AS S_02,
b.score AS S_01
FROM
(
SELECT
*
FROM
50exercises.sc
WHERE
CId = 02
) AS a
LEFT JOIN (
SELECT
*
FROM
50exercises.sc
WHERE
CId = 01
) AS b ON a.SId = b.SId
where b.score IS NULL
2. 查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩
筛选出平均成绩大于60分,和学生表Join
SELECT
b.Sid,
b.Sname,
c.avg_s
FROM
50exercises.student AS b
JOIN (
SELECT
a.SId,
avg(a.score) AS avg_s
FROM
50exercises.sc AS a
GROUP BY
a.Sid
HAVING
avg(a.score) >= 60
) AS c ON b.SId = c.SId
3. 查询在 SC 表存在成绩的学生信息
找出SC表中的学生,然后join学生表
SELECT
a.*
FROM
50exercises.student AS a
JOIN (
SELECT DISTINCT
SId
FROM
50exercises.sc
) AS b ON a.SId = b.SId
4. 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null )
从学生表left join成绩表
SELECT
a.*, b.sum_s
FROM
50exercises.student AS a
LEFT JOIN (
SELECT
SId,
sum(score) AS sum_s
FROM
50exercises.sc
GROUP BY
SId
) AS b ON a.SId = b.SId
4.1 查有成绩的学生信息
从成绩表开始,然后匹配学生表即可
SELECT
SId,
sum(score) AS sum_s
FROM
50exercises.sc
GROUP BY
SId
5. 查询「李」姓老师的数量
找到姓李的老师的表,然后count
SELECT
count(1)
FROM
50exercises.teacher
WHERE Tname LIKE '李%'
6. 查询学过「张三」老师授课的同学的信息
先找出张三老师教的课,然后找到有这么课成绩的学生,然后join学生表
SELECT
*
FROM
50exercises.student AS e
JOIN (
SELECT
c.SId
FROM
50exercises.sc AS c
JOIN (
SELECT
a.CId
FROM
50exercises.course AS a
JOIN (
SELECT
*
FROM
50exercises.teacher
WHERE
Tname = '张三'
) AS b ON a.TId = b.TId
) AS d ON c.CId = d.CId
) AS f ON e.SId = f.SId
7. 查询没有学全所有课程的同学的信息
解法1,由于CId是整数,所以可以相加,那么只要找出不是6的或者为空的就可以
SELECT
*
FROM
student AS a
LEFT JOIN (
SELECT
SId,
SUM(CId) AS sum_cid
FROM
sc
GROUP BY
SId
) AS b ON a.SId = b.SId
WHERE
b.sum_cid <> 6
OR b.sum_cid IS NULL
标准解法,上过所有课的人,在sc表中出现的次数和课程表中课的数量相同,然后反选即可
SELECT
*
FROM
student
WHERE
student.sid NOT IN (
SELECT
sc.sid
FROM
sc
GROUP BY
sc.sid
HAVING
count(sc.cid) = (SELECT count(cid) FROM course)
)
8. 查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息
首先得到学号01的同学学过的课程
select `CId`
from `50exercises`.sc
where `SId`= 01
然后取出至少就是筛选课程在这个范围内的记录,得到Sid
select distinct `SId`
from `50exercises`.sc
where `CId`in(
select `CId`
from `50exercises`.sc
where `SId`= 01
)
最后和信息表组合
select b.*
from
(
select distinct `SId`
from `50exercises`.sc
where `CId`in(
select `CId`
from `50exercises`.sc
where `SId`= 01
)
) as a
join `50exercises`.student as b
on a.SId = b.`SId`
9. 查询和" 01 "号的同学学习的课程 完全相同的其他同学的信息
select c.*
from `50exercises`.sc as a
join `50exercises`.student as c
on a.`SId`=c.`SId`
group by a.SId
having group_concat(a.CId order by a.CId) = (
select group_concat(b.CId order by b.CId)
from `50exercises`.sc as b
where b.SId = "01"
group by b.SId
)
10. 查询没学过"张三"老师讲授的任一门课程的学生姓名
select distinct d.`Sname`
from `50exercises`.teacher as a
join `50exercises`.course as b
on a.`TId`= b.`TId` and a.`Tname` != "张三"
join `50exercises`.sc as c
on b.`CId` = c.`CId`
join `50exercises`.student as d
on c.`SId` = d.`SId`
11. 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
select a.`SId`,
b.`Sname`,
avg(a.score) as avg_score,
sum(if(a.score < 60,1,0)) as smark
from `50exercises`.sc as a
join `50exercises`.student as b
on a.`SId` = b.`SId`
group by a.`SId`
having smark >=2
12. 检索" 01 "课程分数小于 60,按分数降序排列的学生信息
SELECT
*
FROM
sc AS a
JOIN student AS b ON a.SId = b.SId
WHERE
a.CId = "01"
AND a.score < 60
ORDER BY
a.score DESC
13. 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
SELECT
*
FROM
sc AS a
JOIN (
SELECT
Sid,
avg(score) AS AVG_S
FROM
sc
GROUP BY
SId
) AS b ON a.SId = b.Sid
ORDER BY
b.AVG_S DESC
14. 查询各科成绩最高分、最低分和平均分;以如下形式显示:课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率;及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90;要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
SELECT
b.Cname,
b.CId,
max(a.score) AS "最高分",
min(a.score) AS "最低分",
avg(a.score) AS "平均分",
sum(
IF (a.score >= 60 AND a.score < 70, 1, 0)
) / count(DISTINCT Sid) "及格率",
sum(
IF (a.score >= 70 AND a.score < 80, 1, 0)
) / count(DISTINCT Sid) "中等率",
sum(
IF (a.score >= 80 AND a.score < 90, 1, 0)
) / count(DISTINCT Sid) "优良率",
sum(IF(a.score >= 90, 1, 0)) / count(DISTINCT Sid) "优秀率"
FROM
sc AS a
JOIN course AS b ON a.CId = b.CId
GROUP BY
CId
15. 按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺
SELECT
A.CId,
A.SId,
A.score,
IF (
a.cid =@tmid ,@rank :=@rank + 1 ,@rank := 1
) AS rank ,@tmid := a.cid
FROM
(SELECT * from SC order by cid asc,score DESC) AS A,
(SELECT @rank := 0 ,@tmid := NULL) AS B
15.1 按各科成绩进行排序,并显示排名, Score 重复时合并名次
SELECT
A.CId,
A.SId,
A.score,
CASE
WHEN a.cid <> @tmid THEN
@rank := 1
WHEN a.cid = @tmid
AND a.score <> @tscore THEN
@rank :=@rank + 1
WHEN a.cid = @tmid
AND a.score = @tscore THEN
@rank := @rank
ELSE @rank := 1
END AS rank,
@tmid := a.cid,
@tscore := a.score
FROM
(
SELECT
*
FROM
SC
ORDER BY
cid ASC,
score DESC
) AS A,
(
SELECT
@rank := 1 ,@tmid := NULL ,@tscore := 0
) AS B
16. 查询学生的总成绩,并进行排名,总分重复时保留名次空缺
看了下数据,没有总成绩相同的学生,检验不出效果,所以改成用01课程来检验
SELECT
a.SId,
a.all_s,
CASE
WHEN a.all_s <> @tscore then @rank := @rank+1
ELSE @rank = @rank
END as rank,
@tscore := a.all_s
FROM
(
SELECT
SId,
sum(score) AS all_s
FROM
sc
WHERE
Cid = "01"
GROUP BY
SId
ORDER BY
all_s DESC
) AS a,
(SELECT @rank := 0 ,@tscore := 0) AS b
16.1 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺
SELECT
a.SId,
a.all_s,
@rank := @rank+1 as rank
FROM
(
SELECT
SId,
sum(score) AS all_s
FROM
sc
WHERE
Cid = "01"
GROUP BY
SId
ORDER BY
all_s DESC
) AS a,
(SELECT @rank := 0 ) AS b
17. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比
和14题相同
SELECT
b.Cname,
b.CId,
sum(
IF (a.score >= 0 AND a.score < 60, 1, 0)
) / count(DISTINCT Sid) "[0,60)",
sum(
IF (a.score >= 60 AND a.score < 70, 1, 0)
) / count(DISTINCT Sid) "[60,70)",
sum(
IF (a.score >= 70 AND a.score < 85, 1, 0)
) / count(DISTINCT Sid) "[70,85)",
sum(IF(a.score >= 85, 1, 0)) / count(DISTINCT Sid) "[85,100]"
FROM
sc AS a
JOIN course AS b ON a.CId = b.CId
GROUP BY
CId
18. 查询各科成绩前三名的记录
SELECT
*
FROM
sc
WHERE
(
SELECT
count(*)
FROM
sc AS a
WHERE
sc.cid = a.cid
AND sc.score < a.score
) < 3 ##是不是比自己大的有三条
ORDER BY
cid ASC,
sc.score DESC;
解法2
SELECT
a.sid,
a.cid,
a.score
FROM
sc a
LEFT JOIN sc b ON a.cid = b.cid
AND a.score < b.score
GROUP BY
a.cid,
a.sid
HAVING
count(b.cid) < 3
ORDER BY
a.cid;
19. 查询每门课程被选修的学生数
SELECT
CId,
COUNT(DISTINCT SId) AS count_s
FROM
SC
GROUP BY
CId
20. 查询出只选修两门课程的学生学号和姓名
SELECT
*
FROM
(
SELECT
SId,
COUNT(DISTINCT CId) AS count_C
FROM
SC
GROUP BY
SId
HAVING
count_C <= 2
) AS a
JOIN student AS b ON a.SId = b.SId
21. 查询男生、女生人数
SELECT
Ssex,
COUNT(DISTINCT SId) as Qty
FROM
student
GROUP BY
Ssex
22. 查询名字中含有「风」字的学生信息
SELECT
*
FROM
student
WHERE
sname LIKE "%风%"
23. 查询同名同性学生名单,并统计同名人数
SELECT
sname,
COUNT(DISTINCT sid) AS Qty
FROM
student
GROUP BY
Sname
HAVING
qty > 1
24. 查询 1990 年出生的学生名单
SELECT
*
FROM
student
WHERE
YEAR (Sage) = 1990
25. 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
SELECT
CId,
avg(score) AS avg_s
FROM
sc
GROUP BY
CId
ORDER BY
avg_s DESC,
CId ASC
26. 查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
SELECT
a.SId,
a.Sname,
b.avg_s
FROM
student AS a
JOIN (
SELECT
SId,
avg(score) AS avg_s
FROM
sc
GROUP BY
SId
) AS b ON a.SId = b.SId
27. 查询课程名称为「数学」,且分数低于 60 的学生姓名和分数
SELECT
c.Sname,
d.score
FROM
(
SELECT
a.SId,
a.score
FROM
sc AS a
JOIN course AS b ON a.CId = b.CId
WHERE
a.score < 60
AND b.Cname = '数学'
) AS d
JOIN student AS c ON c.SId = d.SId
28. 查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)
SELECT
*
FROM
student AS a
JOIN course AS b
LEFT JOIN sc AS c ON a.SId = c.SId
AND b.CId = c.CId
29. 查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数
SELECT
*
FROM
student AS a
JOIN course AS b
LEFT JOIN sc AS c ON a.SId = c.SId
AND b.CId = c.CId
where score > 70
30. 查询不及格的课程
SELECT
DISTINCT cid
FROM
sc
WHERE
score < 60
31. 查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名
SELECT
b.*
FROM
(
SELECT DISTINCT
Sid
FROM
sc
WHERE
score >= 80
AND Cid = '01'
) AS a
JOIN student AS b ON a.Sid = b.Sid
32. 求每门课程的学生人数
SELECT
cid,
COUNT(DISTINCT sid)
FROM
sc
GROUP BY
CId
33. 成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
SELECT
*
FROM
teacher AS a
JOIN course AS b ON a.TId = b.TId
AND a.Tname = '张三'
JOIN sc AS c ON b.CId = c.CId
JOIN student AS d ON d.SId = c.SId
HAVING
max(c.score)
34. 成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
SELECT
*
FROM
teacher AS a
JOIN course AS b ON a.TId = b.TId
AND a.Tname = '张三'
JOIN sc AS c ON b.CId = c.CId
JOIN student AS d ON d.SId = c.SId
WHERE
c.score = (
SELECT
max(c.score)
FROM
teacher AS a
JOIN course AS b ON a.TId = b.TId
AND a.Tname = '张三'
JOIN sc AS c ON b.CId = c.CId
JOIN student AS d ON d.SId = c.SId
)
35. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
SELECT
a.cid,
a.sid,
a.score
FROM
sc AS a
INNER JOIN sc AS b ON a.sid = b.sid
AND a.cid != b.cid
AND a.score = b.score
GROUP BY
cid,
sid
36. 查询每门功成绩最好的前两名
SELECT
*
FROM
sc
WHERE
(
SELECT
count(*)
FROM
sc AS a
WHERE
sc.cid = a.cid
AND sc.score < a.score
) < 3 ##是不是比自己大的有三条
ORDER BY
cid ASC,
sc.score DESC;
37. 统计每门课程的学生选修人数(超过 5 人的课程才统计)
SELECT
CId,
COUNT(DISTINCT SId) AS Qty
FROM
sc
GROUP BY
CId
HAVING
Qty > 5
38. 检索至少选修两门课程的学生学号
SELECT
SId,
COUNT(DISTINCT CId) AS Qty
FROM
sc
GROUP BY
SId
HAVING
Qty >= 2
39. 查询选修了全部课程的学生信息
SELECT
b.*, COUNT(DISTINCT a.CId) AS Qty
FROM
sc AS a
JOIN student AS b ON a.SId = b.SId
GROUP BY
SId
HAVING
Qty = (
SELECT
COUNT(DISTINCT CId)
FROM
course
)
40. 查询各学生的年龄,只按年份来算
SELECT
*, YEAR (NOW()) - YEAR (Sage) + 1 AS Age
FROM
student
41. 按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一
SELECT
*, TIMESTAMPDIFF(YEAR, Sage, NOW()) AS Age
FROM
student
42. 查询本周过生日的学生
SELECT
*
FROM
student
WHERE
WEEKOFYEAR(Sage) = WEEKOFYEAR(NOW())
43. 查询下周过生日的学生
SELECT
*
FROM
student
WHERE
WEEKOFYEAR(Sage) = WEEKOFYEAR(NOW())+1
44. 查询本月过生日的学生
SELECT
*
FROM
student
WHERE
MONTH(Sage) = MONTH(NOW())
45. 查询下月过生日的学生
SELECT
*
FROM
student
WHERE
MONTH(Sage) = MONTH(NOW())+1