文章问题导向
mysql单表的数据增删改查如何操作?
如何多表联查?
学完这几十条mysql练习,就可以入门了
如果你都有了答案,可以忽略本文章,或去mysql学习导图寻找更多答案
我的目标:让这个鬼东西变得简单,so easy!!!
学前数据准备:先建5个表,和插入一些数据,用于查询练习
学生表
学号sno
姓名sname
性别ssex
班级class
出生年月sbrithday
create table `student`(
`sno` varchar(20) primary key,
`sname` varchar(20) not null,
`ssex` varchar(10) not null,
`class` varchar(20),
`sbirthday` datetime
);
insert into student values('101','大神','男','202001','1988-08-08');
insert into student values('102','李四','男','202002','1988-08-09');
insert into student values('103','王五','女','202001','1988-06-08');
insert into student values('104','秦明','男','202002','1978-06-09');
insert into student values('105','陈锋','女','202003','1948-02-08');
+-----+-------+------+--------+---------------------+
| sno | sname | ssex | class | sbirthday |
+-----+-------+------+--------+---------------------+
| 101 | 大神 | 男 | 202001 | 1988-08-08 00:00:00 |
| 102 | 李四 | 男 | 202002 | 1988-08-09 00:00:00 |
| 103 | 王五 | 女 | 202001 | 1988-06-08 00:00:00 |
| 104 | 秦明 | 男 | 202002 | 1978-06-09 00:00:00 |
| 105 | 陈锋 | 女 | 202003 | 1948-02-08 00:00:00 |
+-----+-------+------+--------+---------------------+
教师表
教师编号tno
教师名称tname
教师性别tsex
出生年月日tbrithday
职称prof
所在部门depart
create table `teacher`(
`tno` varchar(20) primary key,
`tname` varchar(20) not null,
`tsex` varchar(20) not null,
`tbrithday` datetime,
`prof` varchar(20) not null,
`depart` varchar(20) not null
);
insert into teacher values('201','陈老师','男','1978-02-03','副教授', '计算机系');
insert into teacher values('202','李老师','女','1968-04-08','讲师', '电子工程系');
insert into teacher values('203','王老师','男','1958-03-18','讲师', '计算机系');
insert into teacher values('204','唐老师','女','1948-05-07','助教', '电子工程系');
+-----+--------+------+---------------------+--------+------------+
| tno | tname | tsex | tbirthday | prof | depart |
+-----+--------+------+---------------------+--------+------------+
| 201 | 陈老师 | 男 | 1978-02-03 00:00:00 | 副教授 | 计算机系 |
| 202 | 李老师 | 女 | 1968-04-08 00:00:00 | 讲师 | 电子工程系 |
| 203 | 王老师 | 男 | 1958-03-18 00:00:00 | 讲师 | 计算机系 |
| 204 | 唐老师 | 女 | 1948-05-07 00:00:00 | 助教 | 电子工程系 |
+-----+--------+------+---------------------+--------+------------+
课程表
课程号cno
课程名称cname
教师编号tno
create table `course`(
`cno` varchar(20) primary key,
`cname` varchar(20) not null,
`tno` varchar(20) not null,
foreign key(tno) references teacher(tno)
);
insert into course values('301','计算机导论','201');
insert into course values('302','操作系统','204');
insert into course values('303','数字电路','202');
insert into course values('304','高等数学','203');
+-----+------------+-----+
| cno | cname | tno |
+-----+------------+-----+
| 301 | 计算机导论 | 201 |
| 302 | 操作系统 | 204 |
| 303 | 数字电路 | 202 |
| 304 | 高等数学 | 203 |
+-----+------------+-----+
成绩表
学生学号sno
课程号cno
成绩degree
create table `score`(
`sno` varchar(20) not null,
`cno` varchar(20) not null,
`degree` decimal,
foreign key(sno) references student(sno),
foreign key(cno) references course(cno),
primary key(sno, cno)
);
insert into score values('101','301','98');
insert into score values('102','302','88');
insert into score values('103','303','68');
insert into score values('104','301','75');
insert into score values('101','304','100');
+-----+-----+--------+
| sno | cno | degree |
+-----+-----+--------+
| 101 | 301 | 98 |
| 101 | 304 | 100 |
| 102 | 302 | 88 |
| 103 | 303 | 68 |
| 104 | 301 | 75 |
+-----+-----+--------+
成绩等级表
下限low
上限up
评级grade
create table `grade`(
low int(3),
up int(3),
grade char(1)
)
insert into grade values(90,100,'A');
insert into grade values(80,89,'B');
insert into grade values(70,79,'C');
insert into grade values(60,69,'D');
insert into grade values(0,59,'E');
+------+------+-------+
| low | up | grade |
+------+------+-------+
| 90 | 100 | A |
| 80 | 89 | B |
| 70 | 79 | C |
| 60 | 69 | D |
| 0 | 59 | E |
+------+------+-------+
练习:先思考,再看答案(答案在下方)
0.查询202001 和 202002班全体同学的记录
1.查询teacher表depart列的并集
2.查询score表中成绩在60 到 80之间的记录
3.查询score表中成绩为85, 86 或 88的记录
4.查询student表中202001班或性别为女的同学
5.以class降序查询student表的所有记录
6.以cno升序,degree降序查询score表的所有记录
7.查询student表中202001班的学生人数
8.查询score表中的最高分的学生学号和课程号
9.查询score表中每门课的平均成绩
10.查询score表中至少有2名学生选修的课程
11.双表查询:查询所有学生的sname,cno,和degree列
12.三表联查:查询所有学生的sname,cname,和degree列
13.查询202001班学生每门课的平均分
14.查询score表中,选修301课程,并且成绩低于101号同学的301课程成绩的所有同学记录
15.查询score表中,成绩高于101号同学的301课程成绩的所有记录
16.查询和学号为101,103同学同年出生的所有学生的sno,sname,sbirthday列
17.查询'陈老师'任课的学生成绩
18.查询选修课程的同学人数大于5人的教师姓名(只要老师教的课,有超过5人选修,就满足条件)
因为数据不够多,可以改成2,或者自己添加数据
19.查询最高分同学的信息
20.查询所有男教师所教的课程
21.查询选修课程编号为301且成绩至少一个高于选修302课程的同学记录
22.查询出计算机系教师所教课程的成绩表
23.查询所有老师和同学的name, sex, birthday
24.查询所有女教师和女同学的name,sex, birthday
25.查询student中不姓'李'的同学记录
26.查询student中每个学生的姓名和年龄
27.查询student中最大和最小的年龄
28.查询 和'李四' 同性别的所有同学的sname,不要李四
29.查询 和'李四' 同性别的并且同班的所有同学的sname
30.查询所有选修 计算机导论 课程的男同学的成绩表
31.双表查询:查询所有同学的sno, cno, grede列
32.四表联查:查询所有有成绩的同学的名字, 课程, 成绩等级
答案
0. 使用包含条件in
select * from student where class in (202001,202002);
+-----+-------+------+--------+---------------------+
| sno | sname | ssex | class | sbirthday |
+-----+-------+------+--------+---------------------+
| 101 | 大神 | 男 | 202001 | 1988-08-08 00:00:00 |
| 102 | 李四 | 男 | 202002 | 1988-08-09 00:00:00 |
| 103 | 王五 | 女 | 202001 | 1988-06-08 00:00:00 |
| 104 | 秦明 | 男 | 202002 | 1978-06-09 00:00:00 |
+-----+-------+------+--------+---------------------+
1. 使用去重distinct
select distinct depart from teacher;
+------------+
| depart |
+------------+
| 计算机系 |
| 电子工程系 |
+------------+
2.使用条件运算符 或 范围查找
select * from score where degree between 60 and 80;
select * from score where degree > 60 and degree < 80;
+-----+-----+--------+
| sno | cno | degree |
+-----+-----+--------+
| 103 | 303 | 68 |
| 104 | 301 | 75 |
+-----+-----+--------+
3.使用包含运算符
select * from score where degree in(85, 86, 88);
+-----+-----+--------+
| sno | cno | degree |
+-----+-----+--------+
| 102 | 302 | 88 |
+-----+-----+--------+
4.使用条件运算符
select * from student where class = '202001' or ssex = '女';
+-----+-------+------+--------+---------------------+
| sno | sname | ssex | class | sbirthday |
+-----+-------+------+--------+---------------------+
| 101 | 大神 | 男 | 202001 | 1988-08-08 00:00:00 |
| 103 | 王五 | 女 | 202001 | 1988-06-08 00:00:00 |
| 105 | 陈锋 | 女 | 202003 | 1948-02-08 00:00:00 |
+-----+-------+------+--------+---------------------+
5.使用order by
select * from student order by class desc;
+-----+-------+------+--------+---------------------+
| sno | sname | ssex | class | sbirthday |
+-----+-------+------+--------+---------------------+
| 105 | 陈锋 | 女 | 202003 | 1948-02-08 00:00:00 |
| 102 | 李四 | 男 | 202002 | 1988-08-09 00:00:00 |
| 104 | 秦明 | 男 | 202002 | 1978-06-09 00:00:00 |
| 101 | 大神 | 男 | 202001 | 1988-08-08 00:00:00 |
| 103 | 王五 | 女 | 202001 | 1988-06-08 00:00:00 |
+-----+-------+------+--------+---------------------+
6.多个排序
select * from score order by cno asc, degree desc;
+-----+-----+--------+
| sno | cno | degree |
+-----+-----+--------+
| 101 | 301 | 98 |
| 104 | 301 | 75 |
| 102 | 302 | 88 |
| 103 | 303 | 68 |
| 101 | 304 | 100 |
+-----+-----+--------+
7. 使用函数
select count(*) count from student where class = '202001';
+-------+
| count |
+-------+
| 2 |
+-------+
8.使用条件子句,先找到最高分,再找学生学号和课程号
select sno, cno from score where degree=(select max(degree) from score);
+-----+-----+
| sno | cno |
+-----+-----+
| 101 | 304 |
+-----+-----+
9.以cno分组,再使用avg函数计算平均数
一门课:select cno, avg(degree) avg_degree from score where cno = '301';
每门课:select cno, avg(degree) avg_degree from score group by cno;
+-----+------------+
| cno | avg_degree |
+-----+------------+
| 301 | 86.5000 |
| 302 | 88.0000 |
| 303 | 68.0000 |
| 304 | 100.0000 |
+-----+------------+
10. 先分组,再计算筛选
select cno from score group by cno having count(cno) >= 2;
+-----+
| cno |
+-----+
| 301 |
+-----+
11. from后可以多个表,以,隔开, 或使用内联查询
select sname, cno, degree from student,score where student.sno = score.sno;
或
select sname,cno,degree from student inner join score on student.sno = score.sno;
+-------+-----+--------+
| sname | cno | degree |
+-------+-----+--------+
| 大神 | 301 | 98 |
| 大神 | 304 | 100 |
| 李四 | 302 | 88 |
| 王五 | 303 | 68 |
| 秦明 | 301 | 75 |
+-------+-----+--------+
12.三表联查
select sname, cname, degree from student, course, score where student.sno = score.sno and course.cno = score.cno;
+-------+------------+--------+
| sname | cname | degree |
+-------+------------+--------+
| 大神 | 计算机导论 | 98 |
| 秦明 | 计算机导论 | 75 |
| 李四 | 操作系统 | 88 |
| 王五 | 数字电路 | 68 |
| 大神 | 高等数学 | 100 |
+-------+------------+--------+
进阶:按sname升序和degree降序,如果需要limit还可以在后面加
select sname, cname, degree from student, course, score where student.sno = score.sno and course.cno = score.cno order by sname asc, degree desc;
+-------+------------+--------+
| sname | cname | degree |
+-------+------------+--------+
| 大神 | 高等数学 | 100 |
| 大神 | 计算机导论 | 98 |
| 李四 | 操作系统 | 88 |
| 王五 | 数字电路 | 68 |
| 秦明 | 计算机导论 | 75 |
+-------+------------+--------+
13. 原则:复杂的查询,先分段进行
先获取202001班的所有学生学号:select sno from student where class = '202001';
再获取这些学生的所有课程:select * from score where sno in (select sno from student where class='202001');
最后以课程分组和计算平均分:select cno, avg(degree) avg_drgree from score where sno in (select sno from student where class='202001') group by cno;
+-----+------------+
| cno | avg_drgree |
+-----+------------+
| 301 | 98.0000 |
| 304 | 100.0000 |
| 303 | 68.0000 |
+-----+------------+
14. 使用条件子句
先查询101号同学的301号课程成绩:select degree from score where sno = '101' and cno = '301';
再获取301号课程的其他同学:select * from score where cno = '301' and degree < (select degree from score where sno='101' and cno='301');
+-----+-----+--------+
| sno | cno | degree |
+-----+-----+--------+
| 104 | 301 | 75 |
+-----+-----+--------+
15. 使用条件子句
select * from score where degree > (select degree from score where sno = '101' and cno = '301');
+-----+-----+--------+
| sno | cno | degree |
+-----+-----+--------+
| 101 | 304 | 100 |
+-----+-----+--------+
16. 使用year()函数
先获取101,103同学的日期:select year(sbirthday) from student where sno in (101,103);
再获取其他学生:select * from student where year(sbirthday) in (select year(sbirthday) from student where sno in (101,103));
+-----+-------+------+--------+---------------------+
| sno | sname | ssex | class | sbirthday |
+-----+-------+------+--------+---------------------+
| 101 | 大神 | 男 | 202001 | 1988-08-08 00:00:00 |
| 102 | 李四 | 男 | 202002 | 1988-08-09 00:00:00 |
| 103 | 王五 | 女 | 202001 | 1988-06-08 00:00:00 |
+-----+-------+------+--------+---------------------+
17. 多层嵌套查询
分析:成绩需要在成绩表里取,但成绩表里不知道陈老师教的是什么课,需要去课程表里取,课程表里不知道陈老师的编号是多少,需要去老师表里取。
先在teacher获取陈老师的编号:select tno from teacher where tname = '陈老师';
再到course获取陈老师的课程编号:select cno from course where tno = (select tno from teacher where tname = '陈老师');
最后根据课程编号获取学生成绩:select * from score where cno = (select cno from course where tno = (select tno from teacher where tname = '陈老师'));
+-----+-----+--------+
| sno | cno | degree |
+-----+-----+--------+
| 101 | 301 | 98 |
| 104 | 301 | 75 |
+-----+-----+--------+
18. 多层嵌套查询
先获取课程编号,分组,筛选,计算总数:select cno from score group by cno having count(*) >= 2;
再获取老师编号: select tno from course where cno = (select cno from score group by cno having count(*) >= 2);
最后获取老师名字:select * from teacher where tno = (select tno from course where cno=(select cno from score group by cno having count(*) >= 2));
+-----+--------+------+---------------------+--------+----------+
| tno | tname | tsex | tbirthday | prof | depart |
+-----+--------+------+---------------------+--------+----------+
| 201 | 陈老师 | 男 | 1978-02-03 00:00:00 | 副教授 | 计算机系 |
+-----+--------+------+---------------------+--------+----------+
19. 多层嵌套查询
select * from student where sno = (select sno from score where degree in (select max(degree) from score));
+-----+-------+------+--------+---------------------+
| sno | sname | ssex | class | sbirthday |
+-----+-------+------+--------+---------------------+
| 101 | 大神 | 男 | 202001 | 1988-08-08 00:00:00 |
+-----+-------+------+--------+---------------------+
20.
select tno from teacher where tsex = '男';
select * from course where tno in (select tno from teacher where tsex = '男');
+-----+------------+-----+
| cno | cname | tno |
+-----+------------+-----+
| 301 | 计算机导论 | 201 |
| 304 | 高等数学 | 203 |
+-----+------------+-----+
21. 使用any:任何一个
select * from score where cno = '301';
select * from score where cno = '302' and degree > any(select degree from score where cno='301');
+-----+-----+--------+
| sno | cno | degree |
+-----+-----+--------+
| 102 | 302 | 88 |
+-----+-----+--------+
22.稍后补上
23. 双表联查:使用as 和 union联表查询
select tname as name, tsex as sex, tbirthday as birthday from teacher union select sname, ssex, sbirthday from student;
+--------+-----+---------------------+
| name | sex | birthday |
+--------+-----+---------------------+
| 陈老师 | 男 | 1978-02-03 00:00:00 |
| 李老师 | 女 | 1968-04-08 00:00:00 |
| 王老师 | 男 | 1958-03-18 00:00:00 |
| 唐老师 | 女 | 1948-05-07 00:00:00 |
| 大神 | 男 | 1988-08-08 00:00:00 |
| 李四 | 男 | 1988-08-09 00:00:00 |
| 王五 | 女 | 1988-06-08 00:00:00 |
| 秦明 | 男 | 1978-06-09 00:00:00 |
| 陈锋 | 女 | 1948-02-08 00:00:00 |
+--------+-----+---------------------+
24. 双表联查:union联表查询 + where
select tname as name, tsex as sex, tbirthday as birthday from teacher where tsex = '女' union select sname, ssex, sbirthday from student where ssex = '女';
+--------+-----+---------------------+
| name | sex | birthday |
+--------+-----+---------------------+
| 李老师 | 女 | 1968-04-08 00:00:00 |
| 唐老师 | 女 | 1948-05-07 00:00:00 |
| 王五 | 女 | 1988-06-08 00:00:00 |
| 陈锋 | 女 | 1948-02-08 00:00:00 |
+--------+-----+---------------------+
25.使用模糊查询like
select * from student where sname not like '李%';
+-----+-------+------+--------+---------------------+
| sno | sname | ssex | class | sbirthday |
+-----+-------+------+--------+---------------------+
| 101 | 大神 | 男 | 202001 | 1988-08-08 00:00:00 |
| 103 | 王五 | 女 | 202001 | 1988-06-08 00:00:00 |
| 104 | 秦明 | 男 | 202002 | 1978-06-09 00:00:00 |
| 105 | 陈锋 | 女 | 202003 | 1948-02-08 00:00:00 |
+-----+-------+------+--------+---------------------+
26.使用now() + year()
年龄:当前年 - 出生年
select year(sbirthday) from student;
select sname, year(now())-year(sbirthday) as 'age' from student;
+-------+------+
| sname | age |
+-------+------+
| 大神 | 33 |
| 李四 | 33 |
| 王五 | 33 |
| 秦明 | 43 |
| 陈锋 | 73 |
+-------+------+
27. min/max + year + now
注意:时间越多,年龄越小
select year(now())-year(min(sbirthday)) as max_age, year(now())-year(max(sbirthday)) as min_age from student;
+---------+---------+
| max_age | min_age |
+---------+---------+
| 73 | 33 |
+---------+---------+
29. 条件拼接
select sname from student where ssex = (select ssex from student where sname='李四') and sname != '李四';
+-------+
| sname |
+-------+
| 大神 |
| 秦明 |
+-------+
30. 条件拼接
select sname from student where ssex = (select ssex from student where sname='李四') and sname != '李四' and class = (select class from student where sname = '李四');
+-------+
| sname |
+-------+
| 秦明 |
+-------+
30.
select * from student where ssex = '男';
select cno from course where cname = '计算机导论';
select * from score where cno = (select cno from course where cname = '计算机导论') and sno in (select sno from student where ssex = '男');
+-----+-----+--------+
| sno | cno | degree |
+-----+-----+--------+
| 101 | 301 | 98 |
| 104 | 301 | 75 |
+-----+-----+--------+
31.双表查询
select sno, cno, grade from score, grade where degree between low and up;
+-----+-----+-------+
| sno | cno | grade |
+-----+-----+-------+
| 101 | 301 | A |
| 101 | 304 | A |
| 102 | 302 | B |
| 104 | 301 | C |
| 103 | 303 | D |
+-----+-----+-------+
32. 四表联查:学生表,成绩表,课程表,成绩等级表,多表,多条件
全部字段:select * from student as stu, score as sco, course as cou, grade as gra where sco.cno = cou.cno and stu.sno = sco.sno and sco.degree between low and up;
要的字段:select stu.sno, sname, cname, grade from student as stu, score as sco, course as cou, grade as gra where sco.cno = cou.cno and stu.sno = sco.sno and sco.degree between low and up;
+-----+-------+------------+-------+
| sno | sname | cname | grade |
+-----+-------+------------+-------+
| 101 | 大神 | 计算机导论 | A |
| 101 | 大神 | 高等数学 | A |
| 102 | 李四 | 操作系统 | B |
| 103 | 王五 | 数字电路 | D |
| 104 | 秦明 | 计算机导论 | C |
+-----+-------+------------+-------+
后补
暂无
学习更多
mysql学习导图