sql经典练习(包括运行通过代码)

建库

导入数据库并运行

# 学生表 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-05-20' , '男');
​
insert into Student values('04' , '李云龙' , '1990-08-06' , '男');
​
insert into Student values('05' , '周懂眉' , '1991-12-01' , '女');
​
insert into Student values('06' , '吴狄' , '1992-03-01' , '女');
​
insert into Student values('07' , '郑迁津' , '1989-07-01' , '女');
​
insert into Student values('09' , '张三' , '2017-12-20' , '女');
​
insert into Student values('10' , '李小刀' , '2017-12-25' , '女');
​
insert into Student values('11' , '王老五' , '2017-12-30' , '女');
​
insert into Student values('12' , '赵秀' , '2017-01-01' , '女');
​
insert into Student values('13' , '陈烈' , '2018-01-01' , '女');
insert into Student values('14' , '陈烈' , '2018-01-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');
​
insert into Course values('04' , '数学' , '04');

# 教师表 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' , '王天');
insert into Teacher values('04' , '小李子');

# 成绩表 SC
​
create table SC(
​
SId varchar(10),
​
CId varchar(10),
​
score decimal(18,1)); 
​
insert into SC values('01' , '01' ,90); 
​
insert into SC values('01' , '02' , 90); 
​
insert into SC values('01' , '03' , 99); 
​
insert into SC values('02' , '01' , 90); 
​
insert into SC values('02' , '02' , 60); 
​
insert into SC values('02' , '03' , 82); 
​
insert into SC values('03' , '01' , 86); 
​
insert into SC values('03' , '02' , 80); 
​
insert into SC values('03' , '03' , 81); 
​
insert into SC values('04' , '01' , 59); 
​
insert into SC values('04' , '02' , 30); 
​
insert into SC values('04' , '03' , 20); 
​
insert into SC values('05' , '01' , 75); 
​
insert into SC values('05' , '02' , 87); 
​
insert into SC values('06' , '01' , 33); 
​
insert into SC values('06' , '03' , 39); 
​
insert into SC values('07' , '02' , 90); 
​
insert into SC values('07' , '03' , 98);
​
insert into SC values('08' , '01' , 72);

练习题

1.查询' 01 '课程比' 02 '课程成绩高的学生的信息及课程分数

#解决思路:将sc表拆成两个表,代表01和02课程,将3表联合,再设置筛选条件即可(说明,在mysql中不区分大小写)
SELECT *
FROM student s JOIN sc a
ON s.sid=a.sid
INNER JOIN sc b
ON s.sid=b.sid
AND 
b.cid=01 AND a.cid=02
WHERE a.score>b.score

1.1查询同时存在' 01 '课程和' 02 '课程的情况

#解决思路:用课程代码(cid)条件单独筛选出两张表,然后综合条件'同时存在01和02课程(sid)的情况' ,筛选合并出结果
​
SELECT * FROM
(SELECT * FROM SC WHERE cid='01') a INNER JOIN 
(SELECT * FROM SC WHERE cid='02') b 
WHERE a.sid=b.sid

1.2 查询存在' 01 '课程但可能不存在' 02 '课程的情况(不存在时显示为 null )

#解题思路:使用学生id(sid)相同和 课程cid=02 两个条件连接两张表,并筛选出课程01的数据;此处注意02课程不存在时要为空 所以不能放在where 条件后
​
SELECT *
FROM sc a LEFT JOIN sc b
ON a.sid=b.sid AND b.cid='02'
WHERE a.cid='01' 

1.3 查询不存在'01 '课程但存在' 02 '课程的情况

#解题思路:筛选出表中哪些学生不存在课程01(即筛选出某些学生不在 有课程01的表中),再用筛选出来的表内联另外一个课程有02 的表
SELECT * FROM 
(SELECT * FROM sc WHERE sid NOT IN (SELECT sid FROM sc WHERE cid='01')) a 
INNER JOIN sc b  ON
a.sid=b.sid AND b.cid='02'

2.查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩

#解题思路:首先注意是平均分,那就是三门合计平均. 选定特定的三个字段,联合一张成绩大于等于60分的表,根据学生id相同再左联一张表
#(右连接会导致许多字段是NULL,因为右外连接是以右表为基础,右表有的数据全部查出来,不管满不满足条件)
​
SELECT a.sid,b.sname,a.avg_score
 FROM
 (SELECT sid,AVG(score) AS avg_score FROM sc
 GROUP BY sid
HAVING avg_score>=60) a LEFT JOIN student b
 ON a.sid=b.sid

3.查询在 SC 表存在成绩的学生信息

 #解题思路:sc表中有成绩的sid是重复的即每一个学生不止一门成绩,用student表中sid 存在于成绩表的sc表里面的条件,即可查出结果.
 
 SELECT  *FROM
 student WHERE sid IN(SELECT sid FROM sc) 
 

4. 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 NULL )

#解题思路:选课总数和总成绩用 count 和sum 函数算出, 用student 表左外连接 sc表, 再以左表中的sid 进行分组;
​
SELECT a.sid,a.sname,
COUNT(b.cid) AS 'cidCount',
SUM(b.score) AS 'sumScore'
FROM student a LEFT JOIN 
sc b ON a.sid=b.sid 
GROUP BY a.sid
​

4.1 查有成绩的学生信息

#解题思路:重点是有成绩,即学生表中的学生sid在成绩表的有成绩的学生当中;
​
SELECT * FROM 
student 
WHERE sid IN(SELECT sid FROM sc)

5. 查询「李」姓老师的数量

#解题思路:在计算数量时 count要带括号且括号里面有数字,进行匹配时用like语法; COUNT(1)和COUNT(*)作用相同,都是对所有的结果进行count
​
SELECT COUNT(1) FROM Teacher
WHERE tname LIKE '李%'

6. 查询学过「张三峰」老师授课的同学的信息

#解题思路:student表联合sc表才知道什么学生上了什么课,拿了什么成绩;sc表联合course表才知道课程的具体名字;course表联合teacher表才知道 哪门科目是哪个老师教的,再加筛选条件,四表连接;
​
SELECT a.* FROM
student a LEFT JOIN sc b ON a.sid=b.sid
LEFT JOIN Course c ON b.cid=c.cid
LEFT JOIN teacher d ON c.tid=d.tid
WHERE d.tname='张三峰'

7.查询没有学全所有课程的同学的信息

 #解题思路: 所有课程即为course的数量,查询每个学生所学课程数量少于此数量的值即可,即sc表中cid的数量小于 course的总数量的同学信息;
 
SELECT * FROM 
student a LEFT JOIN sc b ON a.sid=b.sid
GROUP BY a.sid
HAVING COUNT(b.sid) <(SELECT COUNT(*) FROM course)

8. 查询至少有一门课与学号为' 01 '的同学所学相同的同学的信息

left join :左连接,返回左表中所有的记录以及右表中连接字段相等的记录。 right join :右连接,返回右表中所有的记录以及左表中连接字段相等的记录。 inner join: 内连接,又叫等值连接,只返回两个表中连接字段相等的行。
#解题思路:所需要的是同学信息,则以student表左联 学生课程sc表,条件为sc表中的cid与'01'学号同学cid相同即可,用DISTINCT来减少重复信息,即满足至少一名同学;(这里用 left join 和inner join 都可)
SELECT  DISTINCT a.* FROM 
student a INNER JOIN sc b ON a.sid=b.sid
WHERE b.cid IN (SELECT cid FROM sc WHERE sid='01')
​

9. 查询和' 01 '号的同学学习的课程 完全相同的其他同学的信息

#解题思路:双重否定来筛选出有课程不相同的同学:先选出课程与01同学完全不同的学生,再筛选出 不在这一堆里面的同学并且不是01同学本人再在有着相同课程的同学中,用课程数量与01同学相同的条件筛选出最终结果;
SELECT b.* FROM
(SELECT * FROM sc WHERE sid NOT IN (SELECT sid FROM sc WHERE cid NOT IN(SELECT cid FROM sc WHERE sid="01")) AND sid!="01") a
LEFT JOIN student b ON a.sid=b.sid
GROUP BY b.sid
HAVING COUNT(cid)=(SELECT COUNT(cid) FROM sc WHERE sid="01")
​

10. 查询没学过"张三峰"老师讲授的任一门课程的学生姓名

#解题思路:四表联合查出张三峰老师所上课程中上过这个课程的学生信息,利用排除法,不在其中的即为没有学过张三峰老师任何一门课程的学生;
SELECT sid,sname FROM student WHERE sid NOT IN 
(SELECT DISTINCT a.sid FROM student a LEFT JOIN sc b ON a.sid=b.sid
LEFT JOIN course c ON b.cid=c.cid LEFT JOIN teacher d ON c.tid=d.tid
WHERE d.tname='张三峰') 

11. 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩

#解题思路:关键条件:sc表中成绩小于60且数量要大于等于2 即大于1; 联合student表,sc表和成绩不及格课程有两门以上的学生id表即可得到答案;

SELECT a.sid,a.sname,AVG(b.score) AS avg_score FROM student a LEFT JOIN sc b ON a.sid=b.sid
INNER JOIN (SELECT sid FROM sc WHERE score < 60 GROUP BY sid HAVING COUNT(1)>1) c ON b.sid=c.sid
GROUP BY a.sid

12.检索" 01 "课程分数小于 60,按分数降序排列的学生信息

#解题思路:联表查询,筛选条件为cid为01,score小于60,并按照成绩降序排序即可;
SELECT a.* ,b.score
FROM Student  a LEFT JOIN SC b ON a.sid=b.sid 
WHERE b.cid='01' AND b.score<60 
ORDER BY b.score DESC

13. 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩

#解题思路:主要是平均成绩的查询,因此需要子查询一个关于平均成绩的表,再与sc表关联,按照平均成绩降序即可;
SELECT a.*,avg_score FROM 
sc a LEFT JOIN (SELECT sid,AVG(score) AS avg_score FROM sc GROUP BY sid) b 
ON a.sid=b.sid ORDER BY avg_score DESC

14.查询各科成绩最高分、最低分和平均分

以如下形式显示:课程 ID,课程 NAME,最高分,最低分,平均分,及格率,中等率,优良率,优秀率 及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90 要求输出课程号和选修人数, 查询结果按人数降序排列,若人数相同,按课程号升序排列

#解题思路:分子表查询,关键在于使用 case when 语句处理 不同课程成绩统计下来的比率,其余字段计算或拼接即可,排序则按照优先级 先后顺序书写;
SELECT a.*,b.Cname FROM
(SELECT CId,MAX(score) AS 最高分,MIN(score) AS 最低分,AVG(score) AS 平均分,COUNT(1)  AS 选修人数,
SUM(CASE WHEN score>=60 THEN 1 ELSE 0 END) / COUNT(1) AS 及格率,
SUM(CASE WHEN score>=70 AND score< 80 THEN 1 ELSE 0 END) / COUNT(1) AS 中等率,
SUM(CASE WHEN score>=80 AND score< 90 THEN 1 ELSE 0 END) / COUNT(1) AS 优良率,
SUM(CASE WHEN score>=90 THEN 1 ELSE 0 END) / COUNT(1) AS 优秀率
FROM SC GROUP BY CId) a 
LEFT JOIN Course b ON a.CId=b.CId
ORDER BY 选修人数 DESC,CId ASC

15. 按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺(即相同成绩排名不同)

#解题思路:不合并名次,即只用取出各科成绩,进行排序再加上排名递增即可.
SELECT 
sid,cid,score,@rank:=@rank+1 AS rk
FROM SC,(SELECT @rank:=0) AS t
ORDER BY score DESC 
​
//合并名次(更具理解度
SELECT a.cid, a.sid, a.score, COUNT(b.score)+1 AS rank
FROM sc AS a
LEFT JOIN sc AS b
ON a.score 
  

(19条消息) sql经典50题之--15. 按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺以千的博客-CSDN博客按各科成绩进行排序,并显示排名

15. 1按各科成绩进行排序,并显示排名, Score 重复时合并名次

#解题思路:排序后,逻辑判断@sco的值是否与前一个值相同,若相同名次不变,不同则加1;
SELECT *,
CASE WHEN (@sco=score) THEN @rank 
ELSE @rank:=@rank+1 
END AS rn,
@sco:=score  -- 保存上一次的分数
​
FROM SC ,(SELECT @rank:=0,@sco:=NULL) AS t 
ORDER BY score DESC

16. 查询学生的总成绩,并进行排名,总分重复时保留名次空缺(即相同成绩排名不同)

#解题思路:学生的总成绩用SUM,排名用@rank去绑定数据(按照成绩顺序累加排名即可),从sc表中取学生id和成绩总和,从另一个新表中赋值两个字段:成绩是否相同,排名.
SELECT 
a.*, @rank:=@rank+1 
FROM 
(SELECT sid,SUM(score) AS scos FROM SC GROUP BY sid ORDER BY scos DESC) a,
(SELECT @rank:=0) b

16.1 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺

#解题思路:学生的总成绩用SUM,排名用@rank去绑定数据,用IF去判断是否成绩相同来取决是否保留名次空缺,从sc表中取学生id和成绩总和,从另一个新表中赋值两个字段:成绩是否相同,排名.
​
SELECT a.*,@rank:=IF(@sco=scoall,@rank,@rank+1) AS rank,@sco:=scoall
FROM 
(SELECT sid ,SUM(score) AS scoall FROM sc GROUP BY sid ORDER BY scoall DESC)a,
(SELECT @sco:=NULL,@rank:=0) b;

17. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比

#解题思路:要得到课程编号与名称得联sc和course表,计算其人数用sum,计算百分比 再用人数值除总人数[count(1)]
​
SELECT a.cid ,b.cname,
SUM(CASE WHEN 0<=score AND score <=60 THEN 1 ELSE 0 END ) AS '[0,60]人数',
SUM(CASE WHEN 0<=score AND score <=60 THEN 1 ELSE 0 END )/COUNT(1)*(100) AS '[0,60](%)',
​
SUM(CASE WHEN 60 
  

18.查询各科成绩前三名的记录

#解题思路:最重要的是前三名这个数量如何取到,利用where条件,自连接筛选出成绩前三位, b.score>a.score是关键,大于号变小于号则为求倒数3名.
SELECT a.*
FROM SC a
WHERE (SELECT COUNT(1) FROM SC b WHERE a.cid=b.cid AND, b.score>a.score)<3
ORDER BY cid DESC,score DESC  

19.查询每门课程被选修的学生数

#解题思路:利用sc表,使用count函数即可计算各个课程被多少人选修
SELECT cid,COUNT(cid) AS cid_sum FROM sc 
GROUP BY cid

20.查询出只选修两门课程的学生学号和姓名

#解题思路:关键在于筛选出只选修两门课的学生,利用count方法去计数筛选,然后联接选出学生名字;
SELECT a.sid,b.sname FROM
(select SID,COUNT(1)  AS 选课数量
from SC
GROUP BY SID 
HAVING COUNT(1) =2 
) a left join Student b on a.sid=b.sid

21.查询男生、女生人数

#解题思路:重点在于 需要将ssex分组,不然数据只有男生;
SELECT ssex,count(1) as 人数
from Student
GROUP BY ssex

22.查询名字中含有「风」字的学生信息

SELECT *
FROM Student
WHERE sname like '%风%'

23.查询同名同性学生名单,并统计同名人数

#解题思路:按照姓名分组,姓名形同的情况下按照性别分组统计人数,如果统计人数大于等于1,那说明这个人就是同名同性的
SELECT sname,ssex,count(sname)
FROM Student
GROUP BY sname,ssex
HAVING count(sname)>1

24.查询 1990 年出生的学生名单

SELECT * 
FROM Student
WHERE YEAR(sage)='1990'

25.查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列

#解题思路:数据在sc一张表中就可以取得,之后按照成绩排列就好,记得另起名字方便调用
SELECT cid,AVG(score) AS avg_score
FROM SC
GROUP BY cid
ORDER BY avg_score DESC,cid ASC

26.查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩

#解题思路:主要是大于等于85的数据要用sc表筛选一下,姓名的信息直接外连接student表即可。
SELECT 
a.sid,
b.sname,
a.avg_score
FROM
(SELECT sid,AVG(score) AS avg_score
FROM SC
GROUP BY sid
HAVING AVG(score)>=85 ) a LEFT JOIN Student b
ON a.sid=b.sid 

27.查询课程名称为「数学」,且分数低于 60 的学生姓名和分数

#解题思路:利用cid在course表中的cname=数学来筛选出课程(用到in)。成绩直接条件 and 即可;
SELECT b.sname, a.score 
FROM SC a
LEFT JOIN Student b ON a.sid=b.sid
WHERE a.cid IN
(SELECT cid FROM Course WHERE cname='数学') AND a.score<60

28.查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)

#解题思路:注意连接时,左连接以左边为准,左边数据全在,右连接原理与左连接相同;
SELECT *
FROM Student a
LEFT JOIN SC b
ON a.sid=b.sid

29.查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数

#解题思路:连接,筛选值
SELECT b.sname,c.cname,a.score
FROM SC a LEFT JOIN Student b 
ON a.sid=b.sid LEFT JOIN Course c ON a.cid=c.cid
WHERE a.score>70

30. 查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名

#解题思路:有条件的连表;
SELECT a.sid,b.sname
FROM
(SELECT sid
from SC
where cid='01' and score>=80) a left JOIN Student b on a.sid=b.sid

31.求每门课程的学生人数

select cid,
count(1) as con
from SC
group by cid
​

32.成绩不重复,查询选修「张三峰」老师所授课程的学生中,成绩最高的学生信息及其成绩

#解题思路:4张表连接起来,按成绩排序降序,取第一条记录,就是成绩最高的;注意:不要用left/right join 连表,因为会保留左/右表的全部数据;
SELECT a.*,b.score
FROM Student a  INNER JOIN SC  b ON a.sid=b.sid
INNER JOIN Course c ON b.cid=c.cid 
INNER JOIN Teacher d ON c.tid=d.tid
WHERE d.Tname='张三峰'
ORDER BY b.score DESC 
LIMIT 1

33.成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩

#解题思路:关键在于找到最高分数是多少,然后用in来判断即可
SELECT a.*,b.CId,score
FROM Student a JOIN SC b ON a.SId = b.SId
JOIN Course c ON b.CId = c.CId
JOIN Teacher d ON c.TId = d.TId
WHERE Tname = '张三峰' AND score IN
(SELECT MAX(score) FROM
SC JOIN Course ON SC.CId = Course.CId
JOIN Teacher ON Course.TId = Teacher.TId
WHERE Tname = '张三峰')

34.查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩

#解题思路:是一个学生的不同课程成绩相同,所以可以拿相同的表关联筛选
SELECT DISTINCT a.* FROM sc a JOIN sc b ON a.SId=b.SId
WHERE a.score=b.score AND a.CId!=b.CId

35.查询每门成绩最好的前两名

#解题思路:自连接,解决排名问题需要用count 来计算A比B成绩小的数据以此来作为排名;
SELECT A.CId,A.SId,A.score,COUNT(B.score) +1  AS ranking
FROM SC A LEFT JOIN SC B 
ON A.CId = B.CId AND A.score 
  

36.统计每门课程的学生选修人数(超过 7 人(包括7人)的课程才统计)

SELECT cid,COUNT(sid) sidnum
FROM sc
GROUP BY cid 
HAVING sidnum >=7

37.检索至少选修两门课程的学生学号

SELECT sid
FROM sc
GROUP BY sid 
HAVING COUNT(cid) >=2

38.查询选修了全部课程的学生信息

#解题思路:主要找出课程数量,然后去用此作为条件筛选;用student表和sc表联合来取得不同学生的cid数量,然后having 过滤
SELECT a.* FROM student a
INNER JOIN sc b ON a.sid=b.sid 
GROUP BY a.sid
HAVING COUNT(cid)=(SELECT COUNT(cid) FROM course)

39.查询各学生的年龄,只按年份来算

#解题思路;主要在于年龄如何换算;关键用法,year取字符串中年的部分
SELECT Sname,Sage,
YEAR(NOW())-YEAR(Sage) AS 年龄 
FROM student

40.按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一

#解法一:利用case when 来解决不同情况下的年龄加减;
SELECT Sname,Sage,
case when (DATE_FORMAT(NOW(),'%m-%d')- DATE_FORMAT(Sage,'%m-%d')) <0
then year(now())-year(Sage)+1
else year(now())-year(Sage) 
end as 年龄
FROM student
​
#解法二:利用timestampDiff
SELECT SId,Sname,TIMESTAMPDIFF(YEAR,Sage,NOW()) AS age
FROM Student

41.查询本周过生日的学生

#解题思路:利用week() 和now()函数
SELECT * FROM student WHERE 
WEEK(Sage)=WEEK(NOW());
#查询下周过生日的学生
SELECT * FROM student where 
week(Sage)=week(now())+1

42.查询本月过生日的学生

SELECT * FROM student WHERE 
MONTH(Sage)=MONTH(NOW())
#查询下个月过生日的
SELECT * FROM student WHERE 
MONTH(Sage)=MONTH(NOW())+1

你可能感兴趣的:(sql,数据库)