Mysql练习:
联表查询:
select score.sid,student.sid from score
left join student on score.student_id=student.sid
left join course on score.course_id=course.cid
left join class on student.class_id=class.cid
left join teacher on teacher.tid=course.teacher_id;
一、请创建如下表,并创建相关约束:
# 数据库 use work;
# 班级表
create table class(
cid int auto_increment primary key,
caption varchar(30) not null
)engine=innodb default charset=utf8;
# 学生表,关联班级表 cid
create table student(
sid int auto_increment primary key,
sname varchar(30) not null,
gender varchar(4) not null default “男”,
class_id int not null,
constraint fk_class_stu foreign key (class_id ) references class(cid)
)engine=innodb default charset=utf8;
# 老师表
create table teacher(
tid int auto_increment primary key,
tname varchar(30) not null
)engine=innodb default charset=utf8;
# 课程表,关联 老师表 tid
create table course(
cid int auto_increment primary key,
cname varchar(30) not null,
teacher_id int not null,
constraint fk_course_teac foreign key (teacher_id) references teacher(tid)
)engine=innodb default charset=utf8;
# 成绩表,关联student sid、 course cid
create table score(
sid int auto_increment primary key,
student_id int not null,
course_id int not null,
number float not null,
constraint fk_score_stu foreign key (student_id) references student(sid),
constraint fk_score_cour foreign key (course_id) references course(cid)
)engine=innodb default charset=utf8;
二、操作表
1、自行创建测试数据
①查询每个学生所在的班级名称:
select * from student left join class on student.class_id=class.cid;
②查询每门课程的老师的姓名:
select * from course left join teacher on course.teacher_id=teacher.tid;
③ 查询每个老师所教了多少门课程:
select teacher_id,count(cname) from course group by teacher_id;
④查询男生女生的个数:
select gender,count(*) from student group by gender;
⑤临时表:
select sid,number from (select * from score where number>90) as B;
select sid from (select sid,number from score where number>90) as B;
2、查询“生物”课程比“物理”课程成绩高的所有学生的学号;
# ①连接student表和core表,分别 查询到学过生物的 as A、学过物理的as B
因为表只能横向对比
(SELECT score.student_id,score.course_id,score.number,course.cname FROM score LEFT JOIN course ON score.course_id=course.cid WHERE course.cname='物理') as A
# ②连接A和B(inner join),然后查询到A.number>B.number的学生id
SELECT A.student_id FROM
(SELECT score.student_id,score.course_id,score.number,course.cname FROM score LEFT JOIN course ON score.course_id=course.cid WHERE course.cname='物理') as A
INNER JOIN
(SELECT score.student_id,score.course_id,score.number,course.cname FROM score LEFT JOIN course ON score.course_id=course.cid WHERE course.cname='生物') as B
ON A.student_id=B.student_id
WHERE A.number>B.number;
3、查询平均成绩大于60分的同学的学号和平均成绩;
思路:
根据学生分组,使用avg获取平均值,通过having对avg进行筛选
select student_id,avg(number) from score group by student_id having avg(number)>60;
扩展:查询平均成绩大于60分的同学的学号、姓名和平均成绩;
SELECT student.sid,student.sname,B.aaa
from student
LEFT JOIN
(select student_id,avg(number) as aaa from score GROUP BY student_id HAVING avg(number)>60) as B
ON student.sid=B.student_id;
4、查询所有同学的学号、姓名、选课数、总成绩;
SELECT student.sid,student.sname,count(student.sid),sum(score.number) from score
LEFT JOIN student on score.student_id=student.sid
GROUP BY student.sid;
5、查询姓“李”的老师的个数;
SELECT count(tid) FROM teacher WHERE tname LIKE '李%' ;
6、查询没学过“叶平”老师课的同学的学号、姓名;
①从score和course表,找到李平老师所教的课程id
SELECT cid FROM teacher LEFT JOIN course ON teacher.tid=course.teacher_id
WHERE teacher.tname=’李平老师'
②从score表筛选出 选过 李平 老师课程的 学生id,并分组去重
SELECT score.student_id FROM score WHERE score.course_id
IN (SELECT cid FROM teacher LEFT JOIN course
ON teacher.tid=course.teacher_id
WHERE teacher.tname='’李平老师') GROUP BY student_id
③ 联合学生表,筛选出 没选过 叶平 老师课的学生id以及姓名
7、查询学过“001”并且也学过编号“002”课程的同学的学号、姓名;
①score表 筛选学过 001 和 002 的学生,
②然后分组,count(course_id)>1的是同时学过这两门课的
③联合student表得到姓名
SELECT score.student_id,student.sname
FROM score LEFT JOIN student on score.student_id=student.sid
WHERE course_id=7 or course_id=8
GROUP BY student_id HAVING count(course_id)>1
8、查询学过“叶平”老师所教的所有课的同学的学号、姓名;
SELECT student.sid,student.sname FROM student WHERE student.sid IN
(SELECT score.student_id FROM score WHERE score.course_id
IN
(SELECT cid FROM teacher LEFT JOIN course
ON teacher.tid=course.teacher_id
WHERE teacher.tname='张益老师') GROUP BY student_id)
9、查询课程编号“002”的成绩比课程编号“001”课程低的所有同学的学号、姓名;
# 学过001的 as A,INNER JOIN,学过002的as B
SELECT student.sid,student.sname FROM
(
SELECT A.student_id,A.course_id FROM
(SELECT * FROM score WHERE course_id=7) as A
INNER JOIN
(SELECT * FROM score WHERE course_id=8) as B
ON A.student_id=B.student_id
WHERE A.number<B.number) as C
LEFT JOIN student
ON C.student_id=student.sid
10、查询有课程成绩小于60分的同学的学号、姓名;
# 先找到成绩<60的,如果遇到某一个同学有多门成绩<60的可以用group by或DISTINCT(DISTINCT去重效率不高)
SELECT sid,sname FROM student WHERE sid IN
(SELECT DISTINCT student_id FROM score WHERE number<70)
#用group去重
SELECT sid,sname FROM student WHERE sid IN
(SELECT student_id FROM score WHERE number<70 GROUP BY student_id)
11、查询没有学全所有课的同学的学号、姓名;
#①查询所学课程数量 小于课程总数的
SELECT student_id,count(1) FROM score GROUP BY student_id
HAVING count(1)<(SELECT COUNT(cid) FROM course);
#②找到姓名
SELECT sid,sname FROM student WHERE sid IN
(SELECT student_id FROM score GROUP BY student_id
HAVING count(1)<(SELECT COUNT(cid) FROM course));
12、查询至少有一门课与学号为“001”的同学所学相同的同学的学号和姓名;
# ①先查询到这位同学选的所有的课
SELECT student_id,course_id FROM score WHERE student_id=1;
# ②在score表中查到学习了这些课程的学生学号,并排除001自己
SELECT student_id FROM score WHERE student_id !=1 AND course_id IN
(SELECT course_id FROM score WHERE student_id=1) GROUP BY student_id);
# ③联表student拿到姓名
SELECT student.sid,student.sname FROM score LEFT JOIN student ON score.student_id=student.sid
WHERE student_id !=1 AND course_id IN
(SELECT course_id FROM score WHERE student_id=1) GROUP BY student_id;
13、查询至少学过学号为“001”同学所选课程中任意一门课的其他同学学号和姓名;
14、查询和“002”号的同学学习的课程完全相同的其他同学学号和姓名
15、删除学习“叶平”老师课的score表记录;
16、向SC表中插入一些记录,这些记录要求符合以下条件:①没有上过编号“002”课程的同学学号;②插入“002”号课程的平均成绩;
#插入score表的值是 查询的结果(其中平均成绩也是动态计算的)
INSERT INTO score(student_id,course_id,number)
SELECT student_id,2,(SELECT avg(number) FROM score WHERE course_id=2) FROM score WHERE course_id!=2;
17、按平均成绩从低到高显示所有学生的“语文”、“数学”、“英语”三门的课程成绩,按如下形式显示: 学生ID,语文,数学,英语,有效课程数,有效平均分;
SELECT
student_id as 学生ID,
(SELECT number FROM score as s2 WHERE s1.student_id=s2.student_id AND course_id=(SELECT cid FROM course WHERE course.cname='生物')) as 生物,
(SELECT number FROM score as s2 WHERE s1.student_id=s2.student_id AND course_id=(SELECT cid FROM course WHERE course.cname='Math')) as 数学,
(SELECT number FROM score as s2 WHERE s1.student_id=s2.student_id AND course_id=(SELECT cid FROM course WHERE course.cname='物理')) as 物理,
count(s1.course_id) as 有效课程数,
avg(s1.number) as 有效平均分
FROM score AS s1
GROUP BY student_id DESC;
18、查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分;
SELECT course_id,MAX(number),MIN(number) FROM score GROUP BY course_id;
扩展:当最低分<10时显示0,大于等于10时显示实际分数
SELECT course_id,max(number),case when min(number)<10 THEN 0 ELSE min(number) END as m FROM score GROUP BY course_id;
19、按各科平均成绩从低到高和及格率的百分数从高到低顺序;
SELECT course_id,avg(number),sum(1),sum(case when number<60 THEN 0 ELSE 1 END)/sum(1) as jigel FROM score
GROUP BY course_id
ORDER BY avg(number) asc,jigel DESC;
20、课程平均分从高到低显示(显示任课老师);
SELECT score.course_id,course.cname,avg(number),teacher.tname FROM score
LEFT JOIN course ON score.course_id=course.cid
LEFT JOIN teacher ON teacher.tid=course.teacher_id
GROUP BY course_id ORDER BY avg(number) desc;
另外:防止分数里面有null就置为0,再做平均分
select avg(if(isnull(score.num),0,score.num)),teacher.tname from course
21、查询各科成绩前三名的记录:(不考虑成绩并列情况)
# 先查询到某一科课程的成绩(避免分数有相同的,用GROUP BY去重)
SELECT number FROM score WHERE course_id=7 GROUP BY number ORDER BY number desc LIMIT 0,1; #课程7第一名
SELECT number FROM score WHERE course_id=7 GROUP BY number ORDER BY number desc LIMIT 1,1; #第二名
SELECT number FROM score WHERE course_id=7 GROUP BY number ORDER BY number desc LIMIT 2,1; #第三名
# 大于第4名的成绩就是前3名
SELECT * FROM
(
SELECT
student_id,course_id,number,
(SELECT number FROM score as s2 WHERE s2.course_id=s1.course_id GROUP BY s2.number ORDER BY s2.number desc LIMIT 0,1),
(SELECT number FROM score as s2 WHERE s2.course_id=s1.course_id GROUP BY s2.number ORDER BY s2.number desc LIMIT 3,1) as cc
FROM score as s1
) as B
WHERE B.number > B.cc
同:第35题
22、查询每门课程被选修的学生数;
SELECT course_id,count(student_id) FROM score GROUP BY course_id;
扩展:查询热门课程(选修人数大于>5的)
SELECT course_id,count(1) FROM score GROUP BY course_id HAVING count(1)>5;
23、查询出只选修了一门课程的全部学生的学号和姓名;
#①查询到只学了一门课程的学生的id
SELECT student_id,count(1) FROM score GROUP BY student_id HAVING count(1)=1
#②联表
SELECT score.student_id,student.sname,count(1) FROM score
LEFT JOIN student ON score.student_id=student.sid
GROUP BY student_id HAVING count(1)=1;
24、查询男生、女生的人数;
SELECT gender,COUNT(1) FROM student GROUP BY gender;
25、查询姓“张”的学生名单;
SELECT * FROM student WHERE sname LIKE '张%';
26、查询同名同姓学生名单,并统计同名人数;
SELECT sname,count(1) FROM student GROUP BY sname;
27、查询每门课程的平均成绩,结果按平均成绩升序排列,平均成绩相同时,按课程号降序排列;
SELECT course_id,avg(if(isnull(number),0,number)) as avg FROM score GROUP BY course_id
ORDER BY avg asc,course_id desc;
28、查询平均成绩大于85的所有学生的学号、姓名和平均成绩;
SELECT score.student_id,student.sname,avg(number) FROM score
LEFT JOIN student ON student.sid=score.student_id
GROUP BY score.student_id HAVING avg(number)>85;
29、查询课程名称为“数学”,且分数低于60的学生姓名和分数;
SELECT score.student_id,student.sname,course.cname,score.number FROM score
LEFT JOIN student ON student.sid=score.student_id
LEFT JOIN course ON score.course_id=course.cid
WHERE course.cname='生物' and score.number<60;
30、查询课程编号为003且课程成绩在80分以上的学生的学号和姓名;
同29题:
SELECT score.student_id,student.sname,course.cname,score.number FROM score
LEFT JOIN student ON student.sid=score.student_id
LEFT JOIN course ON score.course_id=course.cid
WHERE course.cid=7 and score.number>80;
31、求选了课程的学生人数
# 用group by
SELECT count(c) FROM
(SELECT count(course_id) as c FROM score GROUP BY student_id) as A;
# 用distinct
SELECT count(DISTINCT student_id) FROM score;
32、查询选修“杨艳”老师所授课程的学生中,成绩最高的学生姓名及其成绩;
#先找到“杨艳”老师所教课程的课程id
SELECT student.sid,student.sname,score.number FROM score
LEFT JOIN student ON student.sid=score.student_id
WHERE score.course_id IN
(select course.cid FROM teacher LEFT JOIN course
ON teacher.tid=course.teacher_id
WHERE teacher.tname='张益老师')
ORDER BY score.number DESC LIMIT 0,1;
33、查询各个课程及相应的选修人数;
SELECT course.cname,count(1) FROM score
LEFT JOIN course ON course.cid=score.course_id
GROUP BY course_id;
34、查询不同课程但成绩相同的学生的学号、课程号、学生成绩;
#SELECT * FROM t1, t2; 结果有 t1的条数* t2的条数(笛卡尔积)
SELECT s1.student_id,s1.course_id,s1.number FROM score as s1,score s2
WHERE s1.sid != s2.sid AND s1.course_id != s2.course_id AND s1.number=s2.number;
35、查询每门课程成绩最好的前两名;
36、检索至少选修两门课程的学生学号;
SELECT student_id,count(student_id) FROM score
GROUP BY student_id
HAVING count(student_id)>1;
37、查询全部学生都选修的课程的课程号和课程名;
#即score表按照course_id进行分组,每门课程的学生人数=学生的总人数
SELECT course_id,course.cname,count(1) FROM score
LEFT JOIN course ON course.cid=score.course_id
GROUP BY course_id
HAVING count(student_id)=(SELECT count(1) FROM student);
38、查询没学过“叶平”老师讲授的任一门课程的学生姓名;
#①先查询到“叶平”老师任课的课程id
#②从score表中查到学习了叶平老师课的所有学生id(不能直接NOT IN,否则不能完整排除)
#③从student表中找到没有被排除的学生
SELECT * FROM student WHERE student.sid NOT IN
(SELECT score.student_id FROM score WHERE score.course_id IN
(SELECT course.cid FROM course LEFT JOIN teacher ON teacher.tid=course.teacher_id
WHERE teacher.tname='张益老师'));
39、查询两门以上不及格课程的同学的学号及其平均成绩;
#先找到不及格的,再分组计算
SELECT student_id,avg(number) FROM score WHERE number<80 GROUP BY student_id HAVING count(1)>2;
40、检索“004”课程分数小于60,按分数降序排列的同学学号;
SELECT * FROM score WHERE course_id=7 AND number<80 ORDER BY number DESC;
41、删除“002”同学的“001”课程的成绩;
DELETE from score WHERE student_id=2 AND course_id=1;