文章目录
一 表的结构
mysql> use mydb;
Database changed
mysql> show tables;
+----------------+
| Tables_in_mydb |
+----------------+
| course |
| score |
| student |
| teacher |
+----------------+
4 rows in set (0.00 sec)
mysql> select * from course;
+-----+-------+-----+
| cid | cname | tid |
+-----+-------+-----+
| 01 | 语文 | 02 |
| 02 | 数学 | 01 |
| 03 | 英语 | 03 |
+-----+-------+-----+
3 rows in set (0.00 sec)
mysql> select * from score;
+-----+-----+--------+
| sid | cid | sscore |
+-----+-----+--------+
| 01 | 01 | 80 |
| 01 | 02 | 90 |
| 01 | 03 | 99 |
| 02 | 01 | 70 |
| 02 | 02 | 60 |
| 02 | 03 | 80 |
| 03 | 01 | 80 |
| 03 | 02 | 80 |
| 03 | 03 | 80 |
| 04 | 01 | 50 |
| 04 | 02 | 30 |
| 04 | 03 | 20 |
| 05 | 01 | 76 |
| 05 | 02 | 87 |
| 06 | 01 | 31 |
| 06 | 03 | 34 |
| 07 | 02 | 89 |
| 07 | 03 | 98 |
+-----+-----+--------+
18 rows in set (0.00 sec)
mysql> select * from student;
+-----+-------+------------+------+
| sid | sname | sbirth | ssex |
+-----+-------+------------+------+
| 01 | 赵雷 | 1990-01-01 | 男 |
| 02 | 钱电 | 1990-12-21 | 男 |
| 03 | 孙风 | 1990-05-20 | 男 |
| 04 | 李云 | 1990-08-26 | 女 |
| 05 | 周梅 | 1991-12-01 | 女 |
| 06 | 吴兰 | 1992-03-01 | 女 |
| 07 | 郑竹 | 1989-07-01 | 女 |
| 08 | 王菊 | 1990-01-20 | 女 |
| 09 | 王菊 | 1990-02-20 | 女 |
+-----+-------+------------+------+
9 rows in set (0.00 sec)
mysql> select * from teacher;
+-----+-------+
| tid | tname |
+-----+-------+
| 01 | 张三 |
| 02 | 李四 |
| 03 | 王五 |
+-----+-------+
3 rows in set (0.00 sec)
二 50小题
#01、查询"01"课程比"02"课程成绩高的学生的信息及课程分数
SELECT st.sid,sname,sbirth,ssex,sc1.sscore
FROM student st,score sc1,score sc2
WHERE st.sid=sc1.sid AND
sc1.cid='01' AND sc2.cid='02'
AND sc1.sscore>sc2.sscore;
#02、查询"01"课程比"02"课程成绩低的学生的信息及课程分数
SELECT st.sid,sname,sbirth,ssex,sc1.sscore
FROM student st,score sc1,score sc2
WHERE st.sid=sc1.sid
AND sc1.cid='01'
AND sc2.cid='02'
AND sc1.sscore<sc2.sscore;
#03、查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
SELECT st.sid,st.sname,ROUND(AVG(sc.sscore),2)
FROM student st
LEFT JOIN score sc ON sc.sid=st.sid
GROUP BY sc.sid
HAVING AVG(sc.sscore)>=60;
#04查询平均成绩小于60分的同学的学生编号和学生姓名和平均成绩-- (包括有成绩的和无成绩的)
SELECT st.sid,st.sname,ROUND(AVG(sc.sscore),2)
FROM student st
LEFT JOIN score sc
ON sc.sid=st.sid
GROUP BY sc.sid
HAVING AVG(sc.sscore)<60;
#05查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩
SELECT st.sid,st.sname,COUNT(sc.cid),
CASE WHEN SUM(sc.sscore) IS NULL THEN 0.00
ELSE ROUND(SUM(sc.sscore),2)
END AS '总成绩'
FROM student st
LEFT JOIN score sc
ON st.sid=sc.sid
GROUP BY st.sid;
#06 查询"李"姓老师的数量
SELECT COUNT(te.tname)#SELECT COUNT(tname)/SELECT COUNT(*)
FROM teacher te
WHERE tname LIKE"李%";#WHERE tname ="李%"; 失败
#07查询学过"张三"老师授课的同学的信息
SELECT st.*
FROM student st
WHERE st.sid IN
(SELECT sc.sid
FROM score sc
WHERE sc.cid
IN (SELECT c.cid
FROM course c,teacher t
WHERE c.tid=t.tid AND t.tname='张三'));
#08查询没学过"张三"老师授课的同学的信息
SELECT st.*
FROM student st
WHERE st.sid IN( SELECT sc.sid
FROM score sc
WHERE sc.cid
IN
(SELECT c.cid
FROM course c,teacher t
WHERE c.tid=t.tid
AND t.tname!='张三')
);
# 09、查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息
#方式一:
SELECT st.*
FROM student st
WHERE st.sid IN
(SELECT sc.sid
FROM score sc
WHERE sc.sid='01'
AND sc.cid='02');
#10、查询学过编号为"01"但是没有学过编号为"02"的课程的同学的信息
SELECT st.*
FROM student st
WHERE st.sid IN
(SELECT sc.sid
FROM score sc
WHERE sc.sid='01'
AND sc.cid!='02');
#11、查询没有学全所有课程的同学的信息
SELECT st.*
FROM student st
LEFT JOIN score sc ON st.sid=sc.sid
GROUP BY st.sid
HAVING COUNT(sc.sscore)<(
SELECT COUNT(DISTINCT cid)
FROM score
);
#12、查询 至少有一门课与学号为"01" 的同学所学相同的 同学的信息
SELECT DISTINCT student.sid,sname
FROM student,score
WHERE student.sid=score.sid
AND score.cid IN
(SELECT cid
FROM score
WHERE sid='01')
AND student.sid!='01';
#13、查询和"01"号的同学学习的课程完全相同的其他同学的信息
#方式一:【有漏洞】如果最多的课程是四门,就不可以使用课程数量相同来判断
SELECT * FROM student
WHERE sid IN(
SELECT DISTINCT sid
FROM score
WHERE sid NOT IN
(SELECT sid
FROM score
WHERE cid NOT IN
(SELECT cid
FROM score
WHERE sid='01')
)
GROUP BY sid
HAVING COUNT(cid)=(SELECT COUNT(cid)
FROM score
WHERE sid='01'
)
AND sid<>'01');
#方式二:
SELECT *
FROM student
WHERE sid IN(
SELECT r2.sid FROM (
(SELECT sid,cid FROM score WHERE sid="01") AS r1
INNER JOIN (
SELECT sid,cid
FROM score
WHERE sid IN (
SELECT sid FROM score
GROUP BY sid
HAVING sid!="01"
AND COUNT(cid)=(
SELECT COUNT(cid)
FROM score
WHERE sid="01")
)
) AS r2
ON r1.cid=r2.cid)
GROUP BY r2.sid
HAVING COUNT(r2.sid)=(SELECT COUNT(cid)
FROM score
WHERE sid="01")
);
#-- 14、查询没学过"张三"老师讲授的任一门课程的学生姓名
SELECT sname
FROM student
WHERE sid IN (
SELECT sid
FROM score
WHERE cid IN(
SELECT cid
FROM course
WHERE tid !=(
SELECT tid
FROM teacher
WHERE tname="张三"
)
)
);
#-- 15、查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
SELECT student.sid,student.sname,AVG(sscore)
FROM student, score
WHERE student.sid=score.sid AND sscore<60
GROUP BY student.sid
HAVING COUNT(cid)>=2;
# case when then else end
SELECT student.sid,student.sname,AVG(sscore)
FROM student, score
WHERE student.sid=score.sid
GROUP BY student.sid
HAVING SUM(CASE WHEN sscore<60 THEN 1 ELSE 0 END)>=2;
#-- 16、检索"01"课程分数小于60,按分数降序排列的学生信息
SELECT *
FROM student st JOIN
(SELECT sid,sscore
FROM score
WHERE cid='01' AND sscore<60) sid
ON st.sid=sid.sid
ORDER BY sid.sscore DESC;
#-- 17、按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
SELECT student.sid,
SUM(CASE WHEN cid='01' THEN sscore ELSE NULL END ) cid1,
SUM(CASE WHEN cid='02' THEN sscore ELSE NULL END ) cid2,
SUM(CASE WHEN cid='03' THEN sscore ELSE NULL END ) cid3,
AVG(sscore) average
FROM student,score
WHERE student.sid=score.sid
GROUP BY student.sid
ORDER BY average DESC;
/*-- 18.查询各科成绩最高分、最低分和平均分:
以如下形式显示:
课程ID,课程name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90 */
#注意如果case when用于count则else必须是NULL不能是0
SELECT score.cid,course.cname,MAX(sscore),MIN(sscore),AVG(sscore),
ROUND( SUM(CASE WHEN sscore>=60 THEN 1 ELSE 0 END)/COUNT(sscore) ,2) '及格率',
ROUND( SUM(CASE WHEN sscore>=70 AND sscore<=80 THEN 1 ELSE 0 END)/COUNT(sscore) ,2) '中等率',
ROUND( SUM(CASE WHEN sscore>80 AND sscore<90 THEN 1 ELSE 0 END)/COUNT(sscore) ,2)'优良率',
ROUND( SUM(CASE WHEN sscore>=90 THEN 1 ELSE 0 END)/COUNT(sscore) ,2)'优秀率'
FROM score,course WHERE score.cid=course.cid
GROUP BY score.cid;
#-- 19、按各科成绩进行排序,并显示排名
/*group by更强调的是一个整体,就是组,
只能显示一个组里满足聚合函数的一条记录,
partition by 在整体后更强调个体,
能显示组里所有个体的记录*/
SELECT sid, cid,sscore,
ROW_NUMBER() OVER(PARTITION BY cid ORDER BY sscore DESC) rank_cid
FROM score;
#-- 20、查询学生的总成绩并进行排名
#方式一:
/*自定义变量: 申明变量:SET @crank =0;
对变量进行赋值:@crank := @crank +1 ,
赋值操作符 =或:= 使用:查找,比较 运算等 ,
作用域:针对于当前会话(连接)有效,作用域同于会话变量*/
SET @crank =0;
SELECT b.sid, b.a, @crank := @crank +1 AS rank1 FROM
(SELECT sid,SUM(sscore) AS a
FROM score
GROUP BY sid
ORDER BY a DESC) b ;
#为什么排序不对?
SET @crank =0;
SELECT @crank := @crank +1 AS rank1,sc.sid,SUM(sscore) AS a
FROM score sc
GROUP BY sid
ORDER BY a DESC;
#方式二:
SELECT st.sid,st.sname,(CASE WHEN SUM(sc.sscore) IS NULL THEN 0 ELSE SUM(sc.sscore) END) AS '总成绩'
FROM student st
LEFT JOIN score sc
ON sc.sid=st.sid
GROUP BY st.sid ORDER BY SUM(sc.sscore) DESC;
#-- 21、查询 不同老师所教 不同课程 平均分 从高到低显示
SELECT course.tid,teacher.tname,course.cid,AVG(sscore) average
FROM course,teacher,score
WHERE course.tid=teacher.tid AND course.cid=score.cid
GROUP BY course.tid,course.cid
ORDER BY average DESC;
#-- 22、查询所有课程的成绩第2名到第3名的学生信息及该课程成绩
#简单版:
SELECT sid,sscore FROM
(SELECT sid, sscore,
ROW_NUMBER() OVER(PARTITION BY cid ORDER BY sscore DESC) rank_cid
FROM score
) cc
WHERE rank_cid IN (2,3) ;
#升级版:
SELECT st.*,cc.sscore FROM student st,
(SELECT sid, sscore,
ROW_NUMBER() OVER(PARTITION BY cid ORDER BY sscore DESC) rank_cid
FROM score
) cc
WHERE rank_cid IN (2,3)AND st.sid=cc.sid ;
#-- 23、统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[0-60]及所占百分比
SELECT score.cid,course.cname,
ROUND( SUM(CASE WHEN sscore<=100 AND sscore>85 THEN 1 ELSE 0 END)/COUNT(sscore) ,2) '[100-85]百分比',
ROUND( SUM(CASE WHEN sscore>70 AND sscore<85 THEN 1 ELSE 0 END)/COUNT(sscore) ,2)'[85-70]百分比',
ROUND( SUM(CASE WHEN sscore>60 AND sscore<=70 THEN 1 ELSE 0 END)/COUNT(sscore) ,2)'[70-60]百分比',
ROUND( SUM(CASE WHEN sscore<=60 AND sscore>0 THEN 1 ELSE 0 END)/COUNT(sscore) ,2)'[0-60]百分比'
FROM score,course WHERE score.cid=course.cid
GROUP BY score.cid;
#-- 25、查询各科成绩前三名的记录
SELECT cid,
SUM(CASE WHEN rank_cid=1 THEN sscore ELSE NULL END) 'first',
SUM(CASE WHEN rank_cid=2 THEN sscore ELSE NULL END) '2nd',
SUM(CASE WHEN rank_cid=3 THEN sscore ELSE NULL END) '3rd'
FROM (
SELECT cid,sid,sscore,
ROW_NUMBER() OVER (PARTITION BY cid ORDER BY sscore DESC) rank_cid
FROM score
) cc
GROUP BY cid;
#-- 26、查询每门课程被选修的学生数
SELECT cid,COUNT(sid)
FROM score
GROUP BY cid;
#-- 27、查询出只有两门课程的全部学生的学号和姓名
SELECT st.sid,st.sname
FROM student st,score sc
WHERE st.sid=sc.sid
GROUP BY sc.sid HAVING(COUNT(*)=2);
#-- 28、查询男生、女生人数
#为什么错了?
SELECT COUNT(st1.ssex) "男生人数",COUNT(st2.sid)-COUNT(st1.ssex) "女生人数"
FROM student st1,student st2
WHERE st1.ssex='男';
SELECT ssex '性别',COUNT(*) '总人数'
FROM student
GROUP BY ssex;
#-- 29、查询名字中含有"风"字的学生信息
SELECT *
FROM student
WHERE sname LIKE'%风%';
#-- 30、查询同名同性学生名单,并统计同名人数
SELECT sname,COUNT(*) AS NUM
FROM student
GROUP BY sname HAVING (COUNT(student.sid)>1);
#-- 31、查询1990年出生的学生名单
#方式一:必须是Y才可以
SELECT *
FROM student
WHERE DATE_FORMAT(sbirth,'%Y')LIKE'1990';
#方式二:
SELECT *
FROM student
WHERE YEAR(sbirth)='1990';
#-- 32、查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
SELECT cid,AVG(sscore)
FROM score
GROUP BY cid
ORDER BY AVG(sscore) DESC,cid ASC;
#-- 33、查询平均成绩大于等于85的所有学生的学号、姓名和平均成绩
SELECT st.sid,st.sname,ROUND( AVG(sscore),2) '平均成绩'
FROM student st ,score sc
WHERE st.sid=sc.sid
GROUP BY sc.sid HAVING(AVG(sscore)>85);
#-- 34、查询课程名称为"数学",且分数低于60的学生姓名和分数
SELECT sname,'数学',sc2.sscore
FROM student st,(SELECT *
FROM score
WHERE cid=(SELECT cid
FROM course
WHERE cname='数学')
AND sscore<60) sc2
WHERE st.sid=sc2.sid ;
#-- 35、查询所有学生的课程及分数情况;
SELECT st.sid,co.cname,sc.sscore
FROM student st , score sc , course co
WHERE st.sid=sc.sid AND sc.cid=co.cid;
#-- 36、查询任何一门课程成绩在70分以上的姓名、课程名称和分数;
SELECT sname,cname,sscore
FROM score s
JOIN course c ON s.cid=c.cid
JOIN Student stu ON s.sid=stu.sid
WHERE sscore>=70;
#-- 37、查询不及格的课程
SELECT DISTINCT(co.cname)
FROM course co JOIN score sc
ON co.cid=sc.cid
WHERE sc.sscore<60;
#-- 38、查询课程编号为01且课程成绩在80分以上的学生的学号和姓名;
SELECT st.sid,sname
FROM student st
JOIN score sc ON st.sid=sc.sid
WHERE cid='01' AND sscore>=80;
#-- 39、求每门课程的学生人数
SELECT cid,COUNT(*) '人数'
FROM score
GROUP BY cid;
#-- 40、查询选修"张三"老师所授课程的学生中,成绩最高的学生信息及其成绩
SELECT st.*,c.cid,sscore
FROM teacher t JOIN course c ON t.tid=c.tid
JOIN score s ON s.cid = c.cid
JOIN student st ON st.sid = s.sid
WHERE t.tname='张三'
ORDER BY sscore DESC
LIMIT 1;
#-- 41、查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
SELECT DISTINCT a.sid,a.cid,a.sscore
FROM Score a,Score b
WHERE a.cid<>b.cid AND a.sscore=b.sscore;
#-- 42、查询每门功成绩最好的前两名
SELECT t1.*
FROM(SELECT cname,
RANK() OVER(PARTITION BY s.cid ORDER BY sscore DESC) rs,
stu.*
FROM score s
JOIN student stu ON s.sid= stu.sid
JOIN Course c ON c.cid=s.cid
)t1
WHERE t1.rs <=2;
#-- 43、统计每门课程的学生选修人数(超过5人的课程才统计)。
#要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
SELECT cid,COUNT(*)
FROM score
GROUP BY cid HAVING(COUNT(*)>5)
ORDER BY COUNT(*) DESC,cid ASC;
#-- 44、检索至少选修两门课程的学生学号
SELECT sid
FROM score
GROUP BY sid
HAVING COUNT(*)>=2;
#-- 45、查询选修了全部课程的学生信息
SELECT *
FROM student
WHERE sid IN(
SELECT sid
FROM score
GROUP BY sid
HAVING COUNT(*)=(
SELECT COUNT(*)
FROM course
)
);
#-- 46、查询各学生的年龄
#-- 按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一
SELECT sname,sbirth,
(DATE_FORMAT(NOW(),'%Y') - DATE_FORMAT(sbirth,'%Y') -
(CASE WHEN DATE_FORMAT(NOW(),'%m%d') > DATE_FORMAT(sbirth,'%m%d')
THEN 0 ELSE 1 END)
) AS age
FROM student;
#-- 47、查询本周过生日的学生
SELECT * FROM Student
WHERE WEEKOFYEAR(CONCAT(
DATE_FORMAT(CURRENT_DATE,'%Y'),
'-',DATE_FORMAT(Sbirth,'%m-%d')
)
) = WEEKOFYEAR(CURRENT_DATE);
#-- 48、查询下周过生日的学生
SELECT * FROM Student
WHERE WEEKOFYEAR(CONCAT(
DATE_FORMAT(CURRENT_DATE,'%Y'),
'-',DATE_FORMAT(Sbirth,'%m-%d')
)
) = WEEKOFYEAR(CURRENT_DATE)+1;
#-- 49、查询本月过生日的学生
SELECT *
FROM student
WHERE MONTH(sbirth)=MONTH(DATE(NOW()));
#-- 50、查询下月过生日的学生
SELECT *
FROM student
WHERE MONTH(sbirth)=(MONTH(DATE(NOW()))+1);