一、多表查询——建立基础表

  1. ----------------------------------------------'建表'----------------------------------------------
  2. create table dep(
  3. id int primary key auto_increment,
  4. name varchar(20)
  5. );
  6. create table emp(
  7. id int primary key auto_increment,
  8. name varchar(20),
  9. sex enum('male','female') not null default 'male',
  10. age int,
  11. dep_id int
  12. );
  13. #插入数据
  14. insert into dep values
  15. (200,'技术'),
  16. (201,'人力资源'),
  17. (202,'销售'),
  18. (203,'运营'),
  19. (205,"安保部");
  20. insert into emp(name,sex,age,dep_id) values
  21. ('yly','male',18,200),
  22. ('zpx','female',48,201),
  23. ('aaa','male',18,201),
  24. ('bbb','male',28,202),
  25. ('ccc','male',18,203),
  26. ('ddd','female',18,204);
  27. ----------------------------------------------'表结构'----------------------------------------------
  28. mysql> select * from dep;
  29. +-----+--------------+
  30. | id | name |
  31. +-----+--------------+
  32. | 200 | 技术 |
  33. | 201 | 人力资源 |
  34. | 202 | 销售 |
  35. | 203 | 运营 |
  36. | 205 | 安保部 |
  37. +-----+--------------+
  38. mysql> select * from emp;
  39. +----+-------+--------+------+--------+
  40. | id | name | sex | age | dep_id |
  41. +----+-------+--------+------+--------+
  42. | 1 | yly | male | 18 | 200 |
  43. | 2 | zpx | female | 48 | 201 |
  44. | 3 | aaa | male | 18 | 201 |
  45. | 4 | bbb | male | 28 | 202 |
  46. | 5 | ccc | male | 18 | 203 |
  47. | 6 | ddd | female | 18 | 204 |
  48. +----+-------+--------+------+--------+

二、多表查询——连表操作

1、前戏

  1. 要多表查询,可以合并两张表,从而查询对应的数据
  2. 案例一、查询每个人的姓名以及所处部门名称
  3. 方法一、"不合理"
  4. # 笛卡尔积
  5. select * from emp,dep;
  6. mysql> select * from emp,dep;
  7. +----+------+--------+------+--------+-----+--------------+
  8. | id | name | sex | age | dep_id | id | name |
  9. +----+------+--------+------+--------+-----+--------------+
  10. | 1 | yly | male | 18 | 200 | 200 | 技术 |
  11. | 1 | yly | male | 18 | 200 | 201 | 人力资源 |
  12. | 1 | yly | male | 18 | 200 | 202 | 销售 |
  13. | 1 | yly | male | 18 | 200 | 203 | 运营 |
  14. | 1 | yly | male | 18 | 200 | 205 | 安保部 |
  15. | 2 | zpx | female | 48 | 201 | 200 | 技术 |
  16. | 2 | zpx | female | 48 | 201 | 201 | 人力资源 |
  17. | 2 | zpx | female | 48 | 201 | 202 | 销售 |
  18. | 2 | zpx | female | 48 | 201 | 203 | 运营 |
  19. | 2 | zpx | female | 48 | 201 | 205 | 安保部 |
  20. ... # 只显示查询出来的部分表
  21. # 合并成了,但是却查到了每个emp的id和部门的id重复一一对应,没有达到emp.dep_id和dep.id进行对应
  22. 方法二、"不合理,会报错"
  23. mysql> select * from emp,dep where dep_id=id;
  24. ERROR 1052 (23000): Column 'id' in where clause is ambiguous
  25. #报错:where子句中的列“id”不明确,
  26. """
  27. 涉及到多表操作的时候 为了避免表字段重复
  28. 需要在字段名的前面加上表名限制
  29. """
  30. 方法三、"合并表之后,id来源于哪个表很明确,查询得出"
  31. mysql> select emp.name,dep.name from emp,dep where emp.dep_id=dep.id;
  32. +------+--------------+
  33. | name | name |
  34. +------+--------------+
  35. | yly | 技术 |
  36. | zpx | 人力资源 |
  37. | aaa | 人力资源 |
  38. | bbb | 销售 |
  39. | ccc | 运营 |
  40. +------+--------------+
  1. # 1、上述操作并不是合理的连表操作,效率低,太麻烦
  2. # 2、在mysql中,不用上述操作,而是使用mysql给我们几个关键字进行连表操作。

2、连表关键字

  1. 将两张表进行联合时,就可以使用下列四个关键字
  2. inner join 内连接:只连接两表中都存在(有对应关系)的数据
  3. select * from emp inner join dep on emp.dep_id = dep.id;
  4. left join 左连接:以左表为基准展示左表所有的数据没有对应则NULL填充
  5. select * from emp left join dep on emp.dep_id = dep.id;
  6. right join 右连接:以右表为基准展示右表所有的数据没有对应则NULL填充
  7. select * from emp right join dep on emp.dep_id = dep.id;
  8. union 全连接:展示左右两表中所有的数据没有对应则NULL填充
  9. select * from emp left join dep on emp.dep_id = dep.id
  10. union
  11. select * from emp right join dep on emp.dep_id = dep.id;
  12. """
  13. 注意左右连接的时候,以基准的时候,显示的顺序
  14. """

三、多表查询——子查询

  1. # 子查询:其实就是分布操作
  2. 将一张表的查询结果当做另外一条SQL语句的查询条件
  3. 案例一:查询 部门是技术或者人力资源的员工信息
  4. 1.先查询技术和人力资源的部门编号
  5. select id from dep where name in ("技术","人力资源");
  6. 2.根据部门标号去员工表中筛选出对应的员工数据
  7. select * from emp where dep_id in (200,201);
  8. 3.汇总上两步得出答案:
  9. select * from emp where dep_id in (select id from dep where name in ("技术","人力资源"));

四、多表查询——练习题

1、练习的基础表

Navicat导入下面的文件

多表查询导入文件.sql

2、基于上表的练习题(必会)

  1. 1 查询所有的课程的名称以及对应的任课老师姓名
  2. 2 查询平均成绩大于八十分的同学的姓名和平均成绩
  3. 3 查询没有报李平老师课的学生姓名
  4. 4 查询没有同时选修物理课程和体育课程的学生姓名
  5. 5 查询挂科超过两门(包括两门)的学生姓名和班级

解答过程:

  1. 1 查询所有的课程的名称以及对应的任课老师姓名
  2. select cname,tname from course INNER JOIN teacher on course.teacher_id=teacher.tid;
  3. -------------------------------------------------------------------------------------
  4. 2 查询平均成绩大于八十分的同学的姓名和平均成绩
  5. select student_id,AVG(num) from score group by student_id having AVG(num)>80;
  6. -------------------------------------------------------------------------------------
  7. 3 查询没有报李平老师课的学生姓名
  8. 第一步:查李平老师不教哪些课的course.cid
  9. -- select course.cid from course INNER JOIN teacher on course.teacher_id=teacher.tid where tname not in ("李平老师");
  10. 第二步:将student_id分组,里面包含上面的course.cid,并去重
  11. -- 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 ("李平老师"));
  12. 第三步:将student.sid和刚刚表的student_id对应上
  13. SELECT
  14. sname
  15. FROM
  16. student
  17. WHERE
  18. student.sid IN (
  19. SELECT DISTINCT
  20. student_id
  21. FROM
  22. score
  23. WHERE
  24. course_id IN (
  25. SELECT
  26. course.cid
  27. FROM
  28. course
  29. INNER JOIN teacher ON course.teacher_id = teacher.tid
  30. WHERE
  31. tname NOT IN ( "李平老师" )));
  32. -------------------------------------------------------------------------------------
  33. 4 查询没有同时选修物理课程和体育课程的学生姓名
  34. 第一步:score表和course
  35. -- select * from score INNER JOIN course on score.course_id=course.cid;
  36. 第二步:筛选同事选物理以及体育的
  37. -- select student_id from (select * from score INNER JOIN course on score.course_id=course.cid) as t1 GROUP BY student_id HAVING n1 ;
  38. 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 "%体育%物理%";
  39. 第三步:not in
  40. 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 "%体育%物理%");
  41. -------------------------------------------------------------------------------------
  42. 5 查询挂科超过两门(包括两门)的学生姓名和班级
  43. 第一步:score.student_id分组,统计挂科大于等于2
  44. -- select score.student_id from score where num <60 group by score.student_id having count(num) >=2;
  45. 第二步:将classstudent连表
  46. 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、基于上表拓展的练习题(不一定要做)

  1. 2、查询学生表中男女生各有多少人
  2. select gender,count(gender) from student GROUP BY gender;
  3. 3、查询物理成绩等于100的学生的姓名
  4. 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. 5、查询所有学生的学号,姓名,选课数,总成绩 # group by可以将一一对应关系的两个字段一起分组
  6. 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;
  7. 6 查询姓李老师的个数
  8. select COUNT(tid) as "姓李的老师个数" from teacher where tname like "李%";
  9. 8 查询物理课程比生物课程高的学生的学号 #分为物理表和生物表
  10. 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. -------------------------------------------------------------------------------------
  12. 11、查询选修了所有课程的学生姓名
  13. -- 1、找出有几门课程course
  14. -- select COUNT(cid) from course;
  15. -- 2score表以student_id分组,计数course_id in 上面查出来的表格4
  16. -- select student_id from score GROUP BY student_id having count(course_id) in (select COUNT(cid) from course);
  17. -- 3、找出student.sid in student_id
  18. 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));
  19. -------------------------------------------------------------------------------------
  20. 12、查询李平老师教的课程的所有成绩记录
  21. -------------------------------------------------------------------------------------
  22. 13、查询全部学生都选修了的课程号和课程名
  23. -------------------------------------------------------------------------------------
  24. 14、查询每门课程被选修的次数
  25. -------------------------------------------------------------------------------------
  26. 15、查询之选修了一门课程的学生姓名和学号
  27. -------------------------------------------------------------------------------------
  28. 16、查询所有学生考出的成绩并按从高到低排序(成绩去重)
  29. -------------------------------------------------------------------------------------
  30. 17、查询平均成绩大于85的学生姓名和平均成绩
  31. -------------------------------------------------------------------------------------
  32. 18、查询生物成绩不及格的学生姓名和对应生物分数
  33. -------------------------------------------------------------------------------------
  34. 19、查询在所有选修了李平老师课程的学生中,这些课程(李平老师的课程,不是所有课程)平均成绩最高的学生姓名
  35. -------------------------------------------------------------------------------------
  36. 20、查询每门课程成绩最好的前两名学生姓名
  37. -------------------------------------------------------------------------------------
  38. 21、查询不同课程但成绩相同的学号,课程号,成绩
  39. -------------------------------------------------------------------------------------
  40. 22、查询没学过“叶平”老师课程的学生姓名以及选修的课程名称;
  41. -------------------------------------------------------------------------------------
  42. 23、查询所有选修了学号为1的同学选修过的一门或者多门课程的同学学号和姓名;
  43. -------------------------------------------------------------------------------------
  44. 24、任课最多的老师中学生单科成绩最高的学生姓名