习题来自于: http://www.cnblogs.com/wangfengming/articles/7891939.html
习题答案来自于: https://www.cnblogs.com/wangfengming/articles/7978354.html
需要创建的表结构如下:
首先创建学生表 student:
-- 创建学生表 create table student( s_id smallint unsigned not null auto_increment primary key, -- 学生编号 s_name varchar(40) not null, -- 姓名 s_age int not null, -- 年龄 s_sex char(2) not null) -- 性别 insert into student(s_name,s_age,s_sex) values("鲁班",12,"男"); insert into student(s_name,s_age,s_sex) values("貂蝉",20,"女"); insert into student(s_name,s_age,s_sex) values("刘备",35,"男"); insert into student(s_name,s_age,s_sex) values("关羽",34,"男"); insert into student(s_name,s_age,s_sex) values("张飞",33,"女"); select * from student; -- 创建老师表 create table teacher( t_id smallint unsigned not null auto_increment primary key,-- 教师编号 t_name varchar(40) not null) -- 教师姓名 insert into teacher(t_name) values("大王"),("alex"),("egon"),("peiqi") -- 创建课程表 create table course( c_id smallint unsigned not null auto_increment primary key, -- 课程编号 c_name varchar(40) not null, -- 课程名字 t_id smallint unsigned not null) -- 教师编号 insert into course(c_name,t_id) values("python",1),("java",2),("linux",3),("go",2) -- 创建成绩表 create table score( id smallint unsigned not null auto_increment primary key, -- 成绩编号 s_id smallint unsigned not null, -- 学生编号 c_id smallint unsigned not null, -- 课程编号 result int not null) -- 成绩得分 insert into score(s_id,c_id,result) values(1,1,79); insert into score(s_id,c_id,result) values(1,2,77); insert into score(s_id,c_id,result) values(1,3,58); insert into score(s_id,c_id,result) values(2,2,66); insert into score(s_id,c_id,result) values(2,3,77); insert into score(s_id,c_id,result) values(3,1,61); insert into score(s_id,c_id,result) values(3,2,64); insert into score(s_id,c_id,result) values(4,3,70);
1. 查询学习课程"python"比课程 "java" 成绩高的学生的学号;
select t1.s_id,t1.id,t1.result as python_result,t2.result as java_result from score as t1 left JOIN -- 把socre表与只取了c_id=2的socre表进行左连接,连接条件是两者的s_id相等, (select s_id,result from score where c_id=2)as t2 -- 筛选条件是t1的c_id=1(选python成绩) 并且t1.result>t2.result(表示python成绩比java成绩高) on t1.s_id=t2.s_id where t1.c_id=1 and t1.result>t2.result;
运行结果:
2. 查询平均成绩大于65分的同学的姓名和平均成绩(保留两位小数);
select s_name,format(result_avg,2)as result_avg from student inner join -- result_avg是平均成绩 format(resulr_avg,2)对平均成绩保留两位小数 (select s_id,avg(result)as result_avg from score group by s_id having result_avg>65 )as t2 -- 对score表按照s_id分组,计算每一组学生的平均成绩(分组条件是result_avg>65) 然后和student表内链接 on student.s_id=t2.s_id -- 内连接条件是两张表的s_id相等;
运行结果:
3. 查询所有同学的姓名、选课数、总成绩
select s_name,course_number,result_sum from student left join -- 将student表与score表(基于s_id分组,求出每位学生的选课数count(c_id) 总成绩sum(result)) (select s_id,count(c_id)as course_number,sum(result)as result_sum from score group by s_id) as t2 -- 两表左连接 连接条件是s_id相等 on student.s_id=t2.s_id;
运行结果:
4. 查询所有的课程的名称以及对应的任课老师姓名;
采用左连接查询:
select c_name,t_name from course left JOIN (select t_id,t_name from teacher)as t2 on course.t_id=t2.t_id;
运行结果:
5. 查询没学过“alex”老师课的同学的姓名;
方法一 :(思路是好的,但是最后发现group_concat 来判断根本行不通!!)
错误:
select t1.s_ids,t1.c_id from -- 两张临时表左连接 连接字段是c_id score ,这样可以基于两张临时表筛选出t1.s_ids c_id就是选过alex课得学生编号 (select GROUP_CONCAT(s_id)as s_ids,c_id from score group by c_id) as t1 -- 首先按照c_id分组得到t1表 inner join (select c_id from course where t_id =(select t_id from teacher where t_name="alex"))as t2 -- course表中基于t_id=2的条件筛选的c_id得到的t2表 on t1.c_id=t2.c_id;
select s_id,s_name from student where s_id not in (select t1.s_ids from -- 两张临时表左连接 连接字段是c_id score ,这样可以基于两张临时表筛选出t1.s_ids c_id就是选过alex可得学生编号 (select GROUP_CONCAT(s_id)as s_ids,c_id from score group by c_id) as t1 -- 首先按照c_id分组得到t1表 inner join (select c_id from course where t_id =(select t_id from teacher where t_name="alex"))as t2 -- course表中基于t_id=2的条件筛选的c_id得到的t2表 on t1.c_id=t2.c_id)
运行结果:(错误版本):
方法二:(啊 我要崩溃了,先跳过,写不出来了23333)
嗯,我吃完饭回来很随意的写出来了,,,,(所以是刚才饿的宝宝大招没使出来???)
select s_name from student where s_id not in (select s_id from score left join (select c_id as cid from course where t_id=(select t_id from teacher where t_name="alex")) as t2 on score.c_id=t2.cid where cid is not null);
(其实应该用内连接,这样最后cid字段非空的条件就不用加了)
思路就是:首先把 teacher表中t_name 为alex的t_id选出来,然后根据t_id 去course表中找到该老师相应的课程,将该临时表与score表进行连接,连接条件是c_id相等,然后筛选出来的就是上过该老师课的学生s_id ;
接下来就直接去student表中过滤就行了~
6 . 查询学过'python'并且也学过编号'java'课程的同学的姓名;
这个题跟上面那个题思路差不多:
select s_id,s_name from student where s_id in ( select s_id from score -- 将score表与筛选出c_id的临时表进行内链接 inner join (select c_id as cid from course where c_name in ("java","python"))as t2 -- 首先把c_name=java python的c_id 从course表筛选出来 on score.c_id=t2.cid group by s_id having count(c_id)>=2 -- 将连接之后的表按照s_id分组,然后查找count(c_id)>2的那些s_id就是同时选了python和java的同学 );
运行结果: