一、多表查询——建立基础表
----------------------------------------------'建表'----------------------------------------------
create table dep(
id int primary key auto_increment,
name varchar(20)
);
create table emp(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') not null default 'male',
age int,
dep_id int
);
#插入数据
insert into dep values
(200,'技术'),
(201,'人力资源'),
(202,'销售'),
(203,'运营'),
(205,"安保部");
insert into emp(name,sex,age,dep_id) values
('yly','male',18,200),
('zpx','female',48,201),
('aaa','male',18,201),
('bbb','male',28,202),
('ccc','male',18,203),
('ddd','female',18,204);
----------------------------------------------'表结构'----------------------------------------------
mysql> select * from dep;
+-----+--------------+
| id | name |
+-----+--------------+
| 200 | 技术 |
| 201 | 人力资源 |
| 202 | 销售 |
| 203 | 运营 |
| 205 | 安保部 |
+-----+--------------+
mysql> select * from emp;
+----+-------+--------+------+--------+
| id | name | sex | age | dep_id |
+----+-------+--------+------+--------+
| 1 | yly | male | 18 | 200 |
| 2 | zpx | female | 48 | 201 |
| 3 | aaa | male | 18 | 201 |
| 4 | bbb | male | 28 | 202 |
| 5 | ccc | male | 18 | 203 |
| 6 | ddd | female | 18 | 204 |
+----+-------+--------+------+--------+
二、多表查询——连表操作
1、前戏
要多表查询,可以合并两张表,从而查询对应的数据
案例一、查询每个人的姓名以及所处部门名称
方法一、"不合理"
# 笛卡尔积
select * from emp,dep;
mysql> select * from emp,dep;
+----+------+--------+------+--------+-----+--------------+
| id | name | sex | age | dep_id | id | name |
+----+------+--------+------+--------+-----+--------------+
| 1 | yly | male | 18 | 200 | 200 | 技术 |
| 1 | yly | male | 18 | 200 | 201 | 人力资源 |
| 1 | yly | male | 18 | 200 | 202 | 销售 |
| 1 | yly | male | 18 | 200 | 203 | 运营 |
| 1 | yly | male | 18 | 200 | 205 | 安保部 |
| 2 | zpx | female | 48 | 201 | 200 | 技术 |
| 2 | zpx | female | 48 | 201 | 201 | 人力资源 |
| 2 | zpx | female | 48 | 201 | 202 | 销售 |
| 2 | zpx | female | 48 | 201 | 203 | 运营 |
| 2 | zpx | female | 48 | 201 | 205 | 安保部 |
... # 只显示查询出来的部分表
# 合并成了,但是却查到了每个emp的id和部门的id重复一一对应,没有达到emp.dep_id和dep.id进行对应
方法二、"不合理,会报错"
mysql> select * from emp,dep where dep_id=id;
ERROR 1052 (23000): Column 'id' in where clause is ambiguous
#报错:where子句中的列“id”不明确,
"""
涉及到多表操作的时候 为了避免表字段重复
需要在字段名的前面加上表名限制
"""
方法三、"合并表之后,id来源于哪个表很明确,查询得出"
mysql> select emp.name,dep.name from emp,dep where emp.dep_id=dep.id;
+------+--------------+
| name | name |
+------+--------------+
| yly | 技术 |
| zpx | 人力资源 |
| aaa | 人力资源 |
| bbb | 销售 |
| ccc | 运营 |
+------+--------------+
# 1、上述操作并不是合理的连表操作,效率低,太麻烦
# 2、在mysql中,不用上述操作,而是使用mysql给我们几个关键字进行连表操作。
2、连表关键字
将两张表进行联合时,就可以使用下列四个关键字
inner join 内连接:只连接两表中都存在(有对应关系)的数据
select * from emp inner join dep on emp.dep_id = dep.id;
left join 左连接:以左表为基准展示左表所有的数据没有对应则NULL填充
select * from emp left join dep on emp.dep_id = dep.id;
right join 右连接:以右表为基准展示右表所有的数据没有对应则NULL填充
select * from emp right join dep on emp.dep_id = dep.id;
union 全连接:展示左右两表中所有的数据没有对应则NULL填充
select * from emp left join dep on emp.dep_id = dep.id
union
select * from emp right join dep on emp.dep_id = dep.id;
"""
注意左右连接的时候,以基准的时候,显示的顺序
"""
三、多表查询——子查询
# 子查询:其实就是分布操作
将一张表的查询结果当做另外一条SQL语句的查询条件
案例一:查询 部门是技术或者人力资源的员工信息
1.先查询技术和人力资源的部门编号
select id from dep where name in ("技术","人力资源");
2.根据部门标号去员工表中筛选出对应的员工数据
select * from emp where dep_id in (200,201);
3.汇总上两步得出答案:
select * from emp where dep_id in (select id from dep where name in ("技术","人力资源"));
四、多表查询——练习题
1、练习的基础表
Navicat导入下面的文件
2、基于上表的练习题(必会)
1、 查询所有的课程的名称以及对应的任课老师姓名
2、 查询平均成绩大于八十分的同学的姓名和平均成绩
3、 查询没有报李平老师课的学生姓名
4、 查询没有同时选修物理课程和体育课程的学生姓名
5、 查询挂科超过两门(包括两门)的学生姓名和班级
解答过程:
1、 查询所有的课程的名称以及对应的任课老师姓名
select cname,tname from course INNER JOIN teacher on course.teacher_id=teacher.tid;
-------------------------------------------------------------------------------------
2、 查询平均成绩大于八十分的同学的姓名和平均成绩
select student_id,AVG(num) from score group by student_id having AVG(num)>80;
-------------------------------------------------------------------------------------
3、 查询没有报李平老师课的学生姓名
第一步:查李平老师不教哪些课的course.cid号
-- select course.cid from course INNER JOIN teacher on course.teacher_id=teacher.tid where tname not in ("李平老师");
第二步:将student_id分组,里面包含上面的course.cid,并去重
-- SELECT distinct student_id from score where course_id in (select course.cid from course INNER JOIN teacher on course.teacher_id=teacher.tid where tname not in ("李平老师"));
第三步:将student.sid和刚刚表的student_id对应上
SELECT
sname
FROM
student
WHERE
student.sid IN (
SELECT DISTINCT
student_id
FROM
score
WHERE
course_id IN (
SELECT
course.cid
FROM
course
INNER JOIN teacher ON course.teacher_id = teacher.tid
WHERE
tname NOT IN ( "李平老师" )));
-------------------------------------------------------------------------------------
4、 查询没有同时选修物理课程和体育课程的学生姓名
第一步:score表和course表
-- select * from score INNER JOIN course on score.course_id=course.cid;
第二步:筛选同事选物理以及体育的
-- select student_id from (select * from score INNER JOIN course on score.course_id=course.cid) as t1 GROUP BY student_id HAVING n1 ;
select student_id,GROUP_CONCAT(cname) from score INNER JOIN course on score.course_id=course.cid GROUP BY student_id having GROUP_CONCAT(cname) like "%物理%体育%" or GROUP_CONCAT(cname) like "%体育%物理%";
第三步:not in
select * from student where student.sid not in (select student_id from score INNER JOIN course on score.course_id=course.cid GROUP BY student_id having GROUP_CONCAT(cname) like "%物理%体育%" or GROUP_CONCAT(cname) like "%体育%物理%");
-------------------------------------------------------------------------------------
5、 查询挂科超过两门(包括两门)的学生姓名和班级
第一步:score.student_id分组,统计挂科大于等于2的
-- select score.student_id from score where num <60 group by score.student_id having count(num) >=2;
第二步:将class和student连表
select student.sname,class.caption from class INNER JOIN student on class.cid=student.class_id where sid in (select score.student_id from score where num <60 group by score.student_id having count(num) >=2);
3、基于上表拓展的练习题(不一定要做)
2、查询学生表中男女生各有多少人
select gender,count(gender) from student GROUP BY gender;
3、查询物理成绩等于100的学生的姓名
select sname from student where sid in (SELECT student_id from score INNER JOIN course on score.course_id=course.cid where num=100 and cname in ("物理"));
5、查询所有学生的学号,姓名,选课数,总成绩 # group by可以将一一对应关系的两个字段一起分组
select student.sid,student.sname,COUNT(course_id) as "选课数",sum(num) as "总成绩" from student INNER JOIN score on student.sid=score.student_id GROUP BY student.sid,student.sname;
6、 查询姓李老师的个数
select COUNT(tid) as "姓李的老师个数" from teacher where tname like "李%";
8、 查询物理课程比生物课程高的学生的学号 #分为物理表和生物表
SELECT t1.student_id from (select student_id,num as "生物成绩" from score INNER JOIN course on score.course_id=course.cid where cname in ("生物")) as t1 INNER JOIN (select student_id,num as "物理成绩" from score INNER JOIN course on score.course_id=course.cid where cname in ("物理")) as t2 on t1.student_id=t2.student_id where "生物成绩" < "物理成绩";
-------------------------------------------------------------------------------------
11、查询选修了所有课程的学生姓名
-- 1、找出有几门课程course
-- select COUNT(cid) from course;
-- 2、score表以student_id分组,计数course_id in 上面查出来的表格4
-- select student_id from score GROUP BY student_id having count(course_id) in (select COUNT(cid) from course);
-- 3、找出student.sid in student_id
select student.sname from student where student.sid in (select student_id from score GROUP BY student_id having count(course_id) in (select COUNT(cid) from course));
-------------------------------------------------------------------------------------
12、查询李平老师教的课程的所有成绩记录
-------------------------------------------------------------------------------------
13、查询全部学生都选修了的课程号和课程名
-------------------------------------------------------------------------------------
14、查询每门课程被选修的次数
-------------------------------------------------------------------------------------
15、查询之选修了一门课程的学生姓名和学号
-------------------------------------------------------------------------------------
16、查询所有学生考出的成绩并按从高到低排序(成绩去重)
-------------------------------------------------------------------------------------
17、查询平均成绩大于85的学生姓名和平均成绩
-------------------------------------------------------------------------------------
18、查询生物成绩不及格的学生姓名和对应生物分数
-------------------------------------------------------------------------------------
19、查询在所有选修了李平老师课程的学生中,这些课程(李平老师的课程,不是所有课程)平均成绩最高的学生姓名
-------------------------------------------------------------------------------------
20、查询每门课程成绩最好的前两名学生姓名
-------------------------------------------------------------------------------------
21、查询不同课程但成绩相同的学号,课程号,成绩
-------------------------------------------------------------------------------------
22、查询没学过“叶平”老师课程的学生姓名以及选修的课程名称;
-------------------------------------------------------------------------------------
23、查询所有选修了学号为1的同学选修过的一门或者多门课程的同学学号和姓名;
-------------------------------------------------------------------------------------
24、任课最多的老师中学生单科成绩最高的学生姓名