外键进行连表:将class表与student表进行连接,优点省空间,进行约束
一对多、一对一、多对多
create table class (
cid int auto_increment;
caption varchar(100);
)
create table student(
sid int auto_increment;
sname varchar(100);
gender varchar(1);
class_id int;
constraint fk_class foreign key(class_id)
references class(cid)
);
查询连表所有内容
select * from student left join class on student.class_id = class.cid;
select * from student inner join class on student.class_id = class.cid;
inner 与 left 的区别就是,inner 不显示空的列 对比一下
left left 查询后(下面第二题)
inner join 查询后
(select *from score) as B 在内存中暂时存储
限制行
select * from student limit 10 从第10行开始取
select * from student limit 10,5 从第10行开始取5行
排序:
select * from order by id asc #根据列从小到大排序
select * from order by id desc #根据列从大到小排序
select * from order by id desc ,grade asc #根据id从大到小 ,如果相同的值将对他的grader值进行从大到小在一次进行排列
group by student_id 分组
分组:就是将一列中重复的数据变成一个,我们要取 class_id 这一列的值,如果我们 select sid from student group by class_id 将会报错,因为mysql不知道怎样处理,不知道要保存那个相同 class_id中的哪个sid.
注意:当我们对于聚合函数进行二次筛选时,后面必须要使用having 不能在使用where
select class_id,count(class_id) from student group by class_id;
select class_id,max(sid) from student group by class_id;
select class_id,min(sid) from student group by class_id;
sum
avg
select class_id,count(class_id) from student group by class_id having class_id > 3;
例题来自于
在练习前,往里面多点数据最好
思路:select * from student where student_id not in (2,4)
我们要理清楚我们所设置表的每一列的代表的是什么,看下面代码的时候从里面往外面进行看
在 student 表中 sid 代表的就是学生的学号 和 score 表中的 student_id 是使用外键进行连接的
group by 选出选过 小波 老师课程的人
select sid,sname from student where sid not in(
select student_id from score where corse_id in (
select course.cid from course left join teacher on course.cid = teacher_id where teacher.tname = "小波"
) group by student_id
);
思路:将生物和物理的成绩分别保存成临时表,然后进行连表,在使用where对连表中的number进行比较
select A.student_id from
(select score.student_id,course.cname,score.number from score left join course on score.corse_id = course.cid where course.cname = "生物") as A
inner join
(select score.student_id,course.cname,score.number from score left join course on score.corse_id = course.cid where course.cname = "物理") as B
on A.student_id = B.student_id where A.number > B.number;
思路:我们可以将学过课程1或者课程2的人数全都筛选出来,然后进行分组,如果分组的课程数大于一那就说明,在我们筛选的数据中,这个学生学过两个课程。也可以先进性连表,这样简单一点。
注意:不能使用 score.corse_id = 1 and score.corse_id = 2 因为在查询表时,这就是一列,如果这样的话将会报错
select score.student_id,student.sname from score left join student on score.student_id = student.sid where score.corse_id = 1 or score.corse_id = 2 group by student_id having count(student_id) > 1;
思路:只要与学生进行连表,知道姓名,然后对,学号进行分组,就可以使用count函数计算选课数
select score.student_id,student.sname,count(corse_id),sum(score.number) from score left join student on score.student_id = student.sid group by score.student_id;
思路:和题目三一样的思路,就是先找到老师所交的课程,然后将所有选过这门小波老师课程的同学,全部选出来,在进行筛选,因为是老师教的所有课程,所以通过group by 和 count 在此筛选,因为老师可能会随时怎加课程,不固定,所以,我们也不能写死。
select score.student_id,student.sname from score left join student on score.student_id = student.sid where corse_id in (
select course.cid from teacher left join course on teacher.tid = course.teacher_id where teacher.tname = "小波"
) group by score.student_id having count(corse_id) = (select count(course.cid) from teacher left join course on teacher.tid = course.teacher_id where teacher.tname = "小波");
distinct的效率不高,虽然可以去重
select score.student_id,student.sname from score left join student on score.student_id = student.sid where score.number < 60 group by score.student_id ;
select distinct student_id from score where score.number < 60;
下面两种方法都可以
select student_id,student.sname from score left join student on score.student_id = student.sid where corse_id in (
select corse_id from score where student_id = 1
) group by student_id having score.student_id > 1;
select student_id from score where student_id != 1 and corse_id in (
select corse_id from score where student_id = 1
) group by student_id
思路:首先要找到和上题一样,除了自己,有这门 课的所有同学,遇到长的sql语句我们要分开进行看,然后在去理解,静下心。
1.select student_id from score where student_id != 1 group by student_id having count(1) = (select count(1) from score where student_id = 1) #找到除了1号同学,找到与1号同学学过课程相等的所有同学的学号
2.select student_id,score.corse_id from score where student_id in (
select student_id from score where student_id != 1 group by student_id having count(1) = (select count(1) from score where student_id = 1)
) #找到了这些课程相同同学的课程详细的课程
3.and corse_id in (select corse_id from score where student_id = 1) #前面是已经筛选出有相同课程数量的所有同学,加上and就是再次筛选,看看相同课程数量的同学中的详细的课程名,是否在1号同学的课程名之中,如果没有则被group by 再次比较数量,这样就可以筛选出来和1号同学所学课程一样的同学了
select student_id from score where student_id in (
select student_id from score where student_id != 1 group by student_id having count(1) = (select count(1) from score where student_id = 1)
) and corse_id in (select corse_id from score where student_id = 1) group by student_id having count(student_id) = (select count(corse_id) from score where student_id = 1);
思路:select 之后也可以添加一个动态的值,但是必须是一个值,如下的平均值
insert into score(student_id,corse_id,number)
select student_id ,2 , (select avg(number) from score where corse_id = 2)
from score where corse_id != 2;
思路:第9题的进阶版,在select 中就相当与循环,可以通过外部s1进行一个一个的插入,
select
s1.student_id,
(select number from score as s2 where s2.student_id=s1.student_id and corse_id = 1) as 生物 #相当于在内部又设置了一次循环,将外层 s1 的值传递给里面的循环,然后在进行筛选
from score as s1;
select
student_id,
(select number from score as s2 where s2.student_id=s1.student_id and corse_id = 1) as 生物,
(select number from score as s2 where s2.student_id=s1.student_id and corse_id = 2) as 体育,
(select number from score as s2 where s2.student_id=s1.student_id and corse_id = 3) as 物理
from score as s1 group by student_id;
select corse_id ,max(number),min(number) ,case when min(number) < 10 then 0 else min(number) end from score group by corse_id;
select corse_id,number,case when number<60 then 0 else 1 end ,1 from score;
#这样讲及格的设置成1 不及格的设置成0 然后分组之后进行,sum函数,sum(不及格)/sum(及格) 就是及格率
select corse_id,avg(number),sum(case when number<60 then 0 else 1 end) as pass ,sum(1) from score
group by corse_id order by avg(number) asc, pass desc; #根据order by 进行排序
思路:连两次表即可
avg(if(isnull(score.number),0,score.number) #三元运算,计算平均值的时候不能为0
#先使用 isnull 判断一下是否为空,如果为空,就取0,不为空就取自己的数值,这样就不会出现太大的误差
select score.corse_id,course.cname,avg(if(isnull(score.number),0,score.number)) as aveage,teacher.tname
from score
left join course on score.corse_id = course.cid
left join teacher on course.teacher_id = teacher.tid
group by corse_id order by aveage desc
;
思路:利用select中的映射,创建一个大于第三名成绩并且成绩不重复的一列成绩,通过临时表,再去查询里面的值进行筛选。
select * from (
select
student_id,
number,
(select number from score as s2 where s2.corse_id = s1.corse_id group by s2.number order by s2.number limit 2,1) as cc
from score as s1
) as B
where B.number > B.cc;
select corse_id,count(corse_id) from score group by corse_id;
select score.student_id,score.number,student.sname from score left join student on score.student_id = student.sid where score.corse_id = 1 and score.number < 60;
通过练习查找,可以发现他们的规律,遇到查重相关就要使用 group by ,明确各个表中的数据,看出需求,要我们查找哪些数据,我们在进行连表,还要仔细理解 select 中内部的映射,可以很方便,要注意写表加上表的名称,不然会导致数据查询失败。仔细体会,这一篇应该可以解决mysql相关查询方面的问题。
elect score.student_id,score.number,student.sname from score left join student on score.student_id = student.sid where score.corse_id = 1 and score.number < 60;
### 总结
通过练习查找,可以发现他们的规律,遇到查重相关就要使用 group by ,明确各个表中的数据,看出需求,要我们查找哪些数据,我们在进行连表,还要仔细理解 select 中内部的映射,可以很方便,要注意写表加上表的名称,不然会导致数据查询失败。仔细体会,这一篇应该可以解决mysql相关查询方面的问题。
come on !!!