SQL练习

    技术2022-07-11  77

    学生表 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);

    练习题及答案(有自己写的答案有从网上copy的答案)

    -- 1、查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数 SELECT s1.*,s2.class1,s2.class2 FROM student s1, (SELECT t1.SId,t1.score class1,t2.score class2 FROM (SELECT * FROM sc WHERE CId =01 ) t1, (SELECT * FROM sc WHERE CId =02 ) t2 WHERE t1.SId =t2.SId AND t1.score>t2.score) s2 WHERE s1.`SId`=s2.SId -- 1.1 查询同时存在" 01 "课程和" 02 "课程的情况 SELECT * FROM (SELECT * FROM sc WHERE CId=01) t1, (SELECT * FROM sc WHERE CId=02) t2 WHERE t1.SId=t2.SId -- 1.2 查询存在" 01 "课程但可能不存在" 02 "课程的情况(不存在时显示为 null ) SELECT * FROM (SELECT * FROM sc WHERE sc.`CId`=01) t1 LEFT JOIN (SELECT * FROM sc WHERE sc.`CId`=02) t2 ON t1.SId=t2.SId -- 1.3 查询不存在" 01 "课程但存在" 02 "课程的情况 SELECT * FROM sc WHERE SId NOT IN (SELECT SId FROM sc WHERE CId=01) AND CId= 02 -- 2、查询平均成绩大于等于 60 分的同学的学生编号、学生姓名、平均成绩 SELECT t1.SId,t1.Sname,AVG(t2.score) AVG FROM student t1,sc t2 WHERE t1.SId =t2.SId GROUP BY t1.SId HAVING AVG(t2.score)>60 -- 3、查询在 SC 表存在成绩的学生信息 SELECT DISTINCT t1.* FROM student t1,sc t2 WHERE t1.SId=t2.SId AND t2.score IS NOT NULL -- 4、查询所有同学的学生编号、学生姓名、选课总数、所有课程的成绩总和联合查询不会显示没选课的学生: SELECT t1.SId,t1.Sname,COUNT(t2.CId) ClassCount ,SUM(t2.score) TotalScore FROM student t1 RIGHT JOIN sc t2 ON t1.SId=t2.SId GROUP BY t1.Sname -- 如果要显示没选课的学生 SELECT t1.SId,t1.Sname,COUNT(t2.CId) ClassCount ,SUM(t2.score) TotalScore FROM student t1 LEFT JOIN sc t2 ON t1.SId=t2.SId GROUP BY t1.Sname -- 4.1查有成绩的学生信息 SELECT t1.* FROM student t1,sc t2 WHERE t1.SId=t2.Sid AND t2.score IS NOT NULL GROUP BY t1.Sname -- 下面的方式 更简单 SELECT t1.* FROM student t1 WHERE t1.SId IN(SELECT sc.`SId` FROM sc ) -- 下面的方式 更简单2 SELECT * FROM student WHERE EXISTS (SELECT sc.sid FROM sc WHERE student.sid = sc.sid); -- 5、查询「李」姓老师的数量 SELECT COUNT(*) FROM teacher WHERE Tname LIKE '李%' -- 6、查询学过「张三」老师授课的同学的信息 SELECT t5.SId,t5.Sname,t5.Sage,t5.Ssex FROM (SELECT t3.*,t4.TId FROM ( SELECT t1.*,t2.CId FROM student t1 , sc t2 WHERE t1.SId=t2.SId) t3, course t4 WHERE t3.CId=t4.CId) t5, teacher t6 WHERE t5.TId=t6.TId AND t6.Tname="张三" -- 可以直接内连接四张表查询 SELECT student.* FROM student,teacher,course,sc WHERE student.sid = sc.sid AND course.cid=sc.cid AND course.tid = teacher.tid AND tname = '张三'; -- 7、查询没有学全所有课程的同学的信息 -- 注意此处group by 后面要用SId 防止同名学生被去重 SELECT t3.SId,t3.Sname,t3.Sage,t3.Ssex FROM ( SELECT t1.*,t2.CId FROM student t1 LEFT JOIN sc t2 ON t1.SId=t2.SId ) t3 GROUP BY t3.SId HAVING COUNT(t3.CId) < (SELECT COUNT(CId) FROM course) -- 使用having 正向思维 SELECT * FROM student WHERE SId IN ( SELECT t1.SId FROM student t1 LEFT JOIN sc t2 ON t1.SId=t2.SId GROUP BY t1.SId HAVING COUNT(t2.CId)<(SELECT COUNT(CId) FROM course) ) -- 反向思维 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 "的同学所学相同的同学的信息 SELECT DISTINCT t1.* FROM student t1,sc t2 WHERE t1.`SId`=t2.`SId` AND t2.CId IN ( SELECT CId FROM sc WHERE SId =01 ) -- 单表子查询代替多表查询 SELECT * FROM student WHERE student.sid IN ( SELECT sc.sid FROM sc WHERE sc.cid IN( SELECT sc.cid FROM sc WHERE sc.sid = '01' ) ); -- 9、查询和" 01 "号的同学学习的课程完全相同的其他同学的信息 -- 这里使用 GROUP_CONCAT() 会将多行数据 合并为一行 默认用,分隔 -- 且必须排序 否则无法比较 SELECT t1.SId,t1.Sname,t1.Sage,t1.Ssex FROM ( SELECT t1.*, GROUP_CONCAT(t2.`CId` ORDER BY t2.`CId` ASC SEPARATOR ',') course FROM student t1,sc t2 WHERE t1.`SId`=t2.`SId` GROUP BY t1.SId ) t1 WHERE t1.course = (SELECT GROUP_CONCAT(CId ORDER BY CId ASC SEPARATOR ',' ) FROM sc WHERE SId=01 ) AND t1.SId<>01 -- 10、查询没学过"张三"老师讲授的任一门课程的学生姓名 -- 反向思维 SELECT Sname FROM student WHERE SId NOT IN ( SELECT t1.`SId` FROM student t1 LEFT JOIN sc t2 ON t1.`SId`=t2.`SId` WHERE t2.`CId` = ( SELECT CId FROM course WHERE TId = ( SELECT TId FROM teacher WHERE Tname="张三" ) ) ) -- 另一种方法 单表代替多表 SELECT * FROM student WHERE student.sid NOT IN( SELECT sc.sid FROM sc WHERE sc.cid IN( SELECT course.cid FROM course WHERE course.tid IN( SELECT teacher.tid FROM teacher WHERE tname = "张三" ) ) ) -- 还有 这种最简单 SELECT * FROM student WHERE student.sid NOT IN( SELECT sc.sid FROM sc,course,teacher WHERE sc.cid = course.cid AND course.tid = teacher.tid AND teacher.tname= "张三" ); -- 11、查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩 SELECT t1.SId,t1.Sname , AVG(t2.`score`) AVG FROM student t1,sc t2 WHERE t1.Sid=t2.SId AND t1.SId IN ( SELECT SId FROM sc WHERE score < 60 GROUP BY SId HAVING COUNT(CId)>=2 ) GROUP BY t1.SId -- 另一种答案 这里 >1 建议写成 >=2 SELECT student.sid, student.sname, AVG(sc.score) FROM student,sc WHERE student.sid = sc.sid AND sc.score<60 GROUP BY sc.sid HAVING COUNT(*)>1; -- 12、检索" 01 "课程分数小于 60,按分数降序排列的学生信息 SELECT t1.* ,t2.score FROM student t1,sc t2 WHERE t1.SId=t2.`SId` AND t2.CId=01 AND t2.`score`<60 ORDER BY t2.`score` DESC -- 13、按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩 SELECT t1.*,t2.avg FROM sc t1 LEFT JOIN ( SELECT sc.`SId`,AVG(sc.`score`) AVG FROM sc GROUP BY sc.`SId` ) t2 ON t1.`SId`=t2.`SId` ORDER BY t2.avg DESC -- 另一种方式 SELECT * FROM sc LEFT JOIN ( SELECT sid,AVG(score) AS avscore FROM sc GROUP BY sid )r ON sc.sid = r.sid ORDER BY avscore DESC; -- 14、查询各科成绩最高分、最低分和平均分 -- 以如下形式显示:课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率 -- 及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90 -- 要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列 -- 用到 流程控制语句 SELECT sc.CId ,course.`Cname`, MAX(sc.score)AS 最高分, MIN(sc.score)AS 最低分, AVG(sc.score)AS 平均分, COUNT(*)AS 选修人数, SUM(CASE WHEN sc.score>=60 THEN 1 ELSE 0 END )/COUNT(*)AS 及格率, SUM(CASE WHEN sc.score>=70 AND sc.score<80 THEN 1 ELSE 0 END )/COUNT(*)AS 中等率, SUM(CASE WHEN sc.score>=80 AND sc.score<90 THEN 1 ELSE 0 END )/COUNT(*)AS 优良率, SUM(CASE WHEN sc.score>=90 THEN 1 ELSE 0 END )/COUNT(*)AS 优秀率 FROM sc , course WHERE sc.`CId`=course.`CId` GROUP BY sc.CId ORDER BY COUNT(*)DESC, sc.CId ASC -- 15、按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺 -- 用到 自连接 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<b.score AND a.cid = b.cid GROUP BY a.cid, a.sid,a.score ORDER BY a.cid, rank ASC; -- 16、查询学生的总成绩,并进行排名,总分重复时不保留名次空缺 SET @crank=0; SELECT t1.* ,@crank := @crank +1 AS rank FROM ( SELECT sid , SUM(sc.score) total FROM sc GROUP BY sid ORDER BY total DESC ) t1 -- 用到变量 SET @crank=0; SELECT q.sid, total, @crank := @crank +1 AS rank FROM( SELECT sc.sid, SUM(sc.score) AS total FROM sc GROUP BY sc.sid ORDER BY total DESC)q; -- 17、统计各科成绩各分数段人数: -- 课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比 SELECT course.cname, course.cid, SUM(CASE WHEN sc.score<=100 AND sc.score>85 THEN 1 ELSE 0 END) AS "[100-85]", SUM(CASE WHEN sc.score<=85 AND sc.score>70 THEN 1 ELSE 0 END) AS "[85-70]", SUM(CASE WHEN sc.score<=70 AND sc.score>60 THEN 1 ELSE 0 END) AS "[70-60]", SUM(CASE WHEN sc.score<=60 AND sc.score>0 THEN 1 ELSE 0 END) AS "[60-0]" FROM sc LEFT JOIN course ON sc.cid = course.cid GROUP BY sc.cid; -- 18、查询各科成绩前三名的记录 -- 答案 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 t1.`CId`,t1.`Cname`, COUNT(t2.sid) COUNT FROM course t1 LEFT JOIN sc t2 ON t1.`CId`=t2.`CId` GROUP BY t1.`CId` -- 这个答案是错的 SELECT cid, COUNT(sid) FROM sc GROUP BY cid; -- 20、查询出只选修两门课程的学生学号和姓名 SELECT sid,sname FROM student WHERE sid IN ( SELECT sid FROM sc GROUP BY sid HAVING COUNT(cid)=2 ) -- 21 、查询男生、女生人数 SELECT ssex,COUNT(ssex) num FROM student GROUP BY ssex -- 22、查询名字中含有「风」字的学生信息 SELECT * FROM student WHERE sname LIKE '%风%' -- 23、查询同名学生名单,并统计同名人数找到同名的名字并统计个数 -- 统计同名人数找到同名的名字并统计个数 SELECT sname,COUNT(sname) num FROM student GROUP BY sname HAVING COUNT(sname)>=2 -- 嵌套查询列出同名的全部学生的信息 SELECT * FROM student WHERE sname IN( SELECT sname FROM student GROUP BY sname HAVING COUNT(sname)>=2) -- 24、查询 1990 年出生的学生名单 SELECT * FROM student WHERE sage LIKE '1990%' -- 使用函数 SELECT * FROM student WHERE YEAR(sage)=1990 -- 25、查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列 SELECT cid,AVG(score) AVG FROM sc GROUP BY cid ORDER BY AVG DESC , cid ASC -- 有详情 SELECT sc.cid, course.cname, AVG(SC.SCORE) AS average FROM sc, course WHERE sc.cid = course.cid GROUP BY sc.cid ORDER BY average DESC,cid ASC; -- 26、查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩 SELECT t1.`SId`,t1.`Sname`,AVG(t2.`score`) AVG FROM student t1,sc t2 WHERE t1.`SId`=t2.`SId` GROUP BY t1.`SId` HAVING AVG(t2.score)>=85 -- 答案 SELECT student.sid, student.sname, AVG(sc.score) AS aver FROM student, sc WHERE student.sid = sc.sid GROUP BY sc.sid HAVING aver >= 85; -- 27、查询课程名称为「数学」,且分数低于 60 的学生姓名和分数 SELECT t1.sname,t2.score FROM student t1,sc t2,course t3 WHERE t1.sid=t2.sid AND t2.cid =t3.cid AND t3.`Cname`='数学' AND t2.score<60 -- 答案 SELECT student.sname, sc.score FROM student, sc, course WHERE student.sid = sc.sid AND course.cid = sc.cid AND course.cname = "数学" AND sc.score < 60; -- 28、查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况) SELECT t3.`Sname`,t4.cname,t4.score FROM student t3 LEFT JOIN ( SELECT t1.`SId`,t2.`Cname`,t1.`score` FROM sc t1,course t2 WHERE t1.`CId`=t2.`CId` ) t4 ON t3.`SId`=t4.sid -- 答案 SELECT student.sname, cid, score FROM student LEFT JOIN sc ON student.sid = sc.sid; -- 29、查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数 SELECT t3.`Sname`,t4.cname,t4.score FROM student t3 LEFT JOIN ( SELECT t1.`SId`,t2.`Cname`,t1.`score` FROM sc t1,course t2 WHERE t1.`CId`=t2.`CId` ) t4 ON t3.`SId`=t4.sid WHERE t4.score>70 -- 答案 SELECT student.sname, course.cname,sc.score FROM student,course,sc WHERE sc.score>70 AND student.sid = sc.sid AND sc.cid = course.cid; -- 30、查询存在不及格的课程 SELECT DISTINCT t2.`Cname` FROM sc t1,course t2 WHERE t1.cid=t2.cid AND t1.`score`<60 -- 答案 SELECT cid FROM sc WHERE score< 60 GROUP BY cid; -- 31、查询课程编号为 01 且课程成绩在 80 分及以上的学生的学号和姓名 SELECT t1.`SId`,t1.`Sname` FROM student t1,sc t2 WHERE t1.`SId`=t2.`SId` AND t2.`CId`='01' AND t2.score >=80 -- 答案 SELECT student.sid,student.sname FROM student,sc WHERE cid="01" AND score>=80 AND student.sid = sc.sid; -- 32、求每门课程的学生人数 SELECT t1.`Cname`, COUNT(t2.`SId`) 学生人数 FROM course t1 LEFT JOIN sc t2 ON t1.`CId`= t2.`CId` GROUP BY t1.`CId` -- 答案 SELECT sc.CId,COUNT(*) AS 学生人数 FROM sc GROUP BY sc.CId; -- 33、成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩 SELECT t1.*,t2.`score` FROM student t1,sc t2,course t3,teacher t4 WHERE t1.sid=t2.sid AND t2.cid=t3.cid AND t3.`TId`=t4.`TId` AND t4.tname='张三' HAVING MAX(t2.`score`) -- 答案 SELECT student.*, sc.score, sc.cid FROM student, teacher, course,sc WHERE teacher.tid = course.tid AND sc.sid = student.sid AND sc.cid = course.cid AND teacher.tname = "张三" HAVING MAX(sc.score); -- 34、成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩 SELECT t1.*,t2.`score` FROM student t1,sc t2,course t3,teacher t4 WHERE t1.sid=t2.sid AND t2.cid=t3.cid AND t3.`TId`=t4.`TId` AND t4.tname='张三' HAVING t2.`score`= ( SELECT MAX(sc.`score`) FROM sc , course ,teacher WHERE sc.`CId`=course.`CId` AND course.`TId`=teacher.`TId` AND teacher.`Tname`='张三' ) -- 35、查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩 SELECT DISTINCT t1.`SId`, t1.cid,t1.score FROM sc t1 INNER JOIN sc t2 ON t1.`SId`=t2.`SId` WHERE t1.cid != t2.`CId` AND t1.score=t2.`score` -- 答案 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 a.sid,a.cid,a.score FROM sc AS a LEFT JOIN sc AS b ON a.cid = b.cid AND a.score<b.score GROUP BY a.cid, a.sid HAVING COUNT(b.cid)<2 ORDER BY a.cid; -- 37、统计每门课程的学生选修人数(超过 5 人的课程才统计) SELECT t1.`Cname`,COUNT(t2.sid) num FROM course t1 LEFT JOIN sc t2 ON t1.`CId`=t2.`CId` GROUP BY t1.`CId` HAVING COUNT(t2.`SId`)>5 -- 答案 SELECT sc.cid, COUNT(sid) AS cc FROM sc GROUP BY cid HAVING cc >5; -- 38、检索至少选修两门课程的学生学号 SELECT t1.`SId` FROM student t1,sc t2 WHERE t1.`SId`=t2.`SId` GROUP BY t1.`SId` HAVING COUNT(t2.cid)>=2 -- 39、查询选修了全部课程的学生信息 -- GROUP_CONCAT(t2.`CId` ORDER BY t2.`CId` ASC SEPARATOR ',') course SELECT t1.* FROM student t1 , sc t2 WHERE t1.`SId`= t2.`SId` GROUP BY t1.`SId` HAVING COUNT(*)= (SELECT DISTINCT COUNT(*) FROM course) -- 答案 SELECT student.* FROM sc ,student WHERE sc.SId=student.SId GROUP BY sc.SId HAVING COUNT(*) = (SELECT DISTINCT COUNT(*) FROM course ) -- 40、查询各学生的年龄,只按年份来算 SELECT sid 编号, sname 姓名, (YEAR(CURDATE()) - YEAR(student.`Sage`))年龄 FROM student -- 一般都是按照41题的做法来计算年龄 -- 41、按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一 SELECT student.SId AS 学生编号,student.Sname AS 学生姓名, TIMESTAMPDIFF(YEAR,student.Sage,CURDATE()) AS 学生年龄 FROM student -- 42、查询本周过生日的学生 -- 答案 SELECT * FROM student WHERE WEEKOFYEAR(student.Sage)=WEEKOFYEAR(CURDATE()); -- 43、查询下周过生日的学生 SELECT * FROM student WHERE WEEKOFYEAR(student.Sage)=WEEKOFYEAR(CURDATE())+1; -- 44、查询本月过生日的学生 SELECT * FROM student WHERE MONTH(student.Sage)=MONTH(CURDATE()); -- 45、查询下月过生日的学生 SELECT * FROM student WHERE MONTH(student.Sage)=MONTH(CURDATE())+1;
    Processed: 0.012, SQL: 9