多表查询

多个表放在一起联合查询。
学生表 student

id s_no s_name
1 fanmao01 张三
2 fanmao02 李四
3 fanmao03 王大锤
4 fanmao04 张铁柱

成绩表 score

id s_no score
1 fanmao01 80
2 fanmao02 90
3 fanmao03 100

内联 inner join … on

在多表查询的时候,比如上面两个表 ,学生表中的 s_no 跟 成绩表中 s_no 相等。在做两个表查询的时候。
s_no 作为两个表之间的关联纽带。

inner join 表示两个表中 都包含有。

Mysql-04 多表查询 - 图1


  1. 查询 学生表,成绩表,参加考试的每位同学的成绩。 ```sql

select xuesheng.id,xuesheng.s_no,s_name,score from chengji INNER JOIN xuesheng — 内联接 ON xuesheng.s_no = chengji.s_no; — 连接的条件

  1. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/87080/1636083613878-8b133a33-aa1c-47e9-b107-87e902d47699.png#clientId=ued56f69c-6cf4-4&from=paste&height=84&id=uc463c2f8&margin=%5Bobject%20Object%5D&name=image.png&originHeight=168&originWidth=478&originalType=binary&ratio=1&size=9599&status=done&style=none&taskId=u9f4d3601-bc2e-4310-a7eb-84701081680&width=239)
  2. - 因为两个表中 都有id,所有在select 后面使用 student.id 表示使用student中的id
  3. - 因为两个表中都有s_no, student.s_no 表示查看学生表中 s_no;
  4. - 因为两个表中只有一个 s_name,s_score 所以可以只写 s_name, s_score.
  5. 2. 查询 学生表,成绩表,参加考试的每位同学的成绩, 并按照成绩从大到小排序。
  6. ```sql
  7. select xuesheng.id,xuesheng.s_no,s_name,score from chengji
  8. INNER JOIN xuesheng -- 内联接
  9. ON xuesheng.s_no = chengji.s_no; -- 连接的条件
  10. order by score;

练习

表A:图书信息表
image.pngimage.png

问题(写sQL):
1、查询书名“B”开头且2014年(包含2014年)之后购入的书籍清单,显示字段 barcode,name, amount,date

  1. select a.barcode,name,amount,date from a
  2. inner join b
  3. on a.barcode = b.barcode -- 表关联
  4. where name like "B%" and year(date)>=2014; -- 条件

2、统计每部书的总数量,显示字段: barcode,name,总量

  1. select a.barcode , name , sum(amount) 总量 from b
  2. INNER JOIN a on a.Barcode = b.Barcode -- 把表关联
  3. group by a.barcode,name; -- 因为 barcode 对应 name 分组的时候用两个字段分组;

3、统计购入次数大于1次的书,显示字段: barcode,name,购入次数

  1. select a.barcode, name, COUNT(*) as 购入次数 from a
  2. INNER JOIN b on a.Barcode = b.Barcode
  3. GROUP BY b.Barcode, name HAVING COUNT(*)>1;

4、统计每本书的销量,按照销量大小降序排序,显示 barcode, name, 销量;

  1. -- 统计每本书的销量,按照销量大小降序排序,显示 barcode, name, 销量;
  2. SELECT b.barcode,NAME,SUM(amount)FROM a
  3. INNER JOIN b on a.barcode=b.barcode -- 表关联
  4. GROUP BY b.barcode,NAME -- 分组
  5. ORDER BY SUM(amount) DESC ; -- 排序

5、统计销量最高的图书,显示 barcode, name, 销量;

  1. -- 1. 找到最大销量值。
  2. -- 1.1 先找每个书的销量
  3. select barcode,sum(amount) from b GROUP BY barcode;
  4. -- 1.2 排序
  5. select sum(amount) from b GROUP BY barcode order by sum(amount) desc limit 1;
  6. -- 2 barcode, name, 销量
  7. select a.barcode,name,sum(amount) as 销量 from a
  8. INNER JOIN b ON a.Barcode = b.Barcode
  9. GROUP BY a.barcode,name
  10. HAVING 销量=100; -- 100 是上一句查询出来的结果
  11. -- 3 合并语句
  12. select a.barcode,name,sum(amount) as 销量 from a
  13. INNER JOIN b ON a.Barcode = b.Barcode
  14. GROUP BY a.barcode,name
  15. -- 100 替换为具体的查询语句
  16. HAVING 销量=(select sum(amount) from b GROUP BY barcode order by sum(amount) desc limit 1);

左联 left join … on

左联和内联的区别:
内联取两个表共有的。
左联是以 左表 为主,跟另外一张表关联,如果另外一张表中,没有对应的值,就显示为Null。

image.pngimage.png


学生表和成绩表
关系: xuesheng.s_no = chengji.s_no

查询所有同学的考试成绩。显示 学号(s_no),姓名(s_name),成绩(score);
因为要查看所有的学生,以学生表 为主。 xuesheng 表作为左表。

  1. select xuesheng.s_no,s_name,score from xuesheng -- xuesheng 主表
  2. left join chengji
  3. on xuesheng.s_no = chengji.s_no;

image.png

右连right join

跟左连接原理一样,以右表为主。
市场上 90% 的开发人员习惯使用左连。

举个例子

  1. SELECT * from xuesheng
  2. RIGHT JOIN chengji
  3. ON xuesheng.s_no = chengji.s_no;

right join 后面跟 chengji 表,所以是以chengji表为主表, chengji表中有个 fanmao06的学号,但是学生表中没有这个学号,查询出来的结果就会为空。
image.png

查询 chengji 表与 kecheng 表, chengji为主表。使用右连。

  1. select chengji.c_no,c_name,score from kecheng
  2. right join chengji
  3. on chengji.c_no = kecheng.c_no;

union 连接

Mysql数据库中不支持外连接,使用 union 连接查询的结果。

  1. SELECT count(*) from students
  2. WHERE sex = "man"
  3. UNION
  4. SELECT count(*) from students
  5. WHERE sex = "woman"

在两个select语句之间 使用 union 可以将两个结果放到一起;
image.png
查询students表中,显示语文分数最高的同学,数学分数最高的同学;
分别找出语文最高分,数学最高分,然后使用union 合并到一起;

  1. -- 语文最高分
  2. select max(score) from students where course = "语文";
  3. select max(score) from students where course = "数学";
  4. -- 使用 union 连接结果
  5. SELECT * FROM students WHERE score = (select max(score) from students where course = "语文") AND course = "语文"
  6. UNION
  7. SELECT * FROM students WHERE score = (select max(score) from students where course = "数学") AND course = "数学"
  8. UNION
  9. SELECT * FROM students WHERE score = (select max(score) from students where course = "英语") AND course = "英语"

练习

image.png

  1. 统计每个同学的参与考试成绩, 显示学号,姓名,科目,成绩

分析: 需要使用到 3张表
Mysql-04 多表查询 - 图10

  1. select xuesheng.s_no,s_name,c_name,score from xuesheng
  2. inner join chengji on xuesheng.s_no = chengji.s_no
  3. inner join kecheng on kecheng.c_no = chengji.c_no -- 三个表关联
  1. 查询每个同学考试的成绩, 显示 学号s_no, 姓名 s_name, 科目 c_name ,成绩 score ,老师名字t_name;
    1. select xuesheng.s_no, s_name,c_name,score,t_name from chengji
    2. INNER JOIN xuesheng on xuesheng.s_no = chengji.s_no
    3. INNER JOIN kecheng on kecheng.c_no = chengji.c_no
    4. INNER JOIN laoshi on laoshi.t_no = kecheng.t_no;

作业

参考
Mysql-练习题

Mysql-04 多表查询 - 图11

  1. 统计参加的每门课程的人数, 显示 课程名c_name,数量。 ```sql select c_name, count(*) from chengji INNER JOIN kecheng on chengji.c_no = kecheng.c_no GROUP BY c_name;
  1. 2. 统计平均分最高的科目
  2. ```sql
  3. -- 1. 找到最高的值
  4. select avg(score) from chengji GROUP BY c_no ORDER BY avg(score) desc limit 1 ;
  5. -- 2. 根据值找到对应的科目 -- 97.5
  6. -- 找到平均分为97.5 的科目
  7. SELECT c_no, avg(score) from chengji
  8. GROUP BY c_no
  9. HAVING avg(score) = 97.5; -- c4 ,c3
  10. -- 3 找到对应的科目
  11. SELECT c_no, avg(score) as 平均分 from chengji
  12. GROUP BY c_no
  13. HAVING avg(score) = (select avg(score) from chengji GROUP BY c_no ORDER BY avg(score) desc limit 1); -- 临时表
  14. -- 合并
  15. select c_name, 平均分 from kecheng
  16. INNER JOIN
  17. -- 上面的结果作为临时表
  18. ( SELECT c_no, avg(score) as 平均分 from chengji
  19. GROUP BY c_no
  20. HAVING avg(score) = (select avg(score) from chengji GROUP BY c_no ORDER BY avg(score) desc limit 1) ) as tmp
  21. on kecheng.c_no = tmp.c_no;

第二种写法

  1. -- 1. 找到最高的值
  2. select avg(score) from chengji GROUP BY c_no ORDER BY avg(score) desc limit 1 ;
  3. -- 2 找到等于最高分的科目
  4. SELECT c_name,AVG(score) from kecheng
  5. INNER JOIN chengji on kecheng.c_no = chengji.c_no
  6. -- 关联表之后 再做过滤
  7. GROUP BY chengji.c_no,c_name
  8. HAVING AVG(score) = ( -- 平均分最高
  9. select avg(score) from chengji GROUP BY c_no ORDER BY avg(score) desc limit 1
  10. )
  1. 统计每个学生的总分

    1. SELECT s_name, sum(score) FROM xuesheng
    2. LEFT JOIN chengji on xuesheng.s_no = chengji.s_no
    3. GROUP BY xuesheng.s_no, s_name
  2. 统计总分最高的学生姓名,总分。 ```sql — 最高分 SELECT sum(score) FROM xuesheng LEFT JOIN chengji on xuesheng.s_no = chengji.s_no GROUP BY xuesheng.s_no, s_name ORDER BY SUM(score) DESC LIMIT 1;

— 找人 SELECT s_name, sum(score) FROM xuesheng LEFT JOIN chengji on xuesheng.s_no = chengji.s_no GROUP BY xuesheng.s_no, s_name HAVING SUM(score) = ( SELECT sum(score) FROM xuesheng LEFT JOIN chengji on xuesheng.s_no = chengji.s_no GROUP BY xuesheng.s_no, s_name ORDER BY SUM(score) DESC LIMIT 1 );

  1. 5. 统计参加考试的科目中 每门课成绩 都大于60分的学生 姓名,科目,成绩。
  2. ```sql
  3. -- 最小分 大于60 的学号
  4. SELECT s_no from chengji
  5. GROUP BY s_no
  6. HAVING min(score) > 60;
  7. SELECT s_name,c_name,score from xuesheng
  8. INNER JOIN chengji on xuesheng.s_no = chengji.s_no
  9. INNER JOIN kecheng on chengji.c_no = kecheng.c_no
  10. where xuesheng.s_no in (SELECT s_no from chengji
  11. GROUP BY s_no
  12. HAVING min(score) > 60)