MySQL----多表查询
作者:mmseoamin日期:2023-12-25

MySQL----多表查询

    • 多表关系
      • 表与表之间的联系:
      • 一对多(多对一)
      • 多对多
      • 一对一
      • 多表查询
      • 多表查询的分类
      • 数据准备
      • 内连接
      • 外连接
      • 自连接
      • 联合查询
      • 子查询
        • 标量子查询
        • 列子查询
        • 行子查询
        • 表子查询
        • 多表查询案例

          多表关系

          在进行数据库表结构的设计时,会根据业务的需求和业务模块之间的关系,分析设计表结构,由于业务之间相互关联,所以各个表结构之间也存在各种联系

          表与表之间的联系:

          1.一对多(多对一)

          2.多对多

          3.一对一

          一对多(多对一)

          例如,一个员工对应一个部门,一个部门可以对应多个员工

          MySQL----多表查询,在这里插入图片描述,第1张

          一般在多的一方创建外键,指向一的那一方

          员工与部门,在员工表上设置外键,指向部门表

          多对多

          例如,一个学生可以选修多门课程,一个课程可以被多名学生选修

          一般会建立第三张表,至少包含两个外键,分别指向两张表的主键

          MySQL----多表查询,在这里插入图片描述,第2张

          一对一

          例如,用户和自己的学历信息的关系,一个人只对应一条学历信息

          可以在任意一方加入外键,关联另一方的主键,并且设置外键为唯一(unique)

          MySQL----多表查询,在这里插入图片描述,第3张

          注:可以放在一张表中,但是对其进行拆分,一张表放基础信息,另一张表放详情,可以提升操作效率

          多表查询

          概述:

          从多张表中查询数据

          笛卡尔积:

          笛卡尔积为两个集合(两张表)中的每条数据进行两两组合的结果

          在多表查询时会产生笛卡尔积,要通过添加条件消除笛卡尔积

          MySQL----多表查询,在这里插入图片描述,第4张

          dept表:

          MySQL----多表查询,请添加图片描述,第5张

          emp表:

          MySQL----多表查询,请添加图片描述,第6张

          查询产生笛卡尔积的结果:

          select * from emp, dept ;
          

          MySQL----多表查询,请添加图片描述,第7张

          消除笛卡尔积(添加条件):

          select * from emp, dept where emp.dept_id=dept.id;
          

          MySQL----多表查询,请添加图片描述,第8张

          多表查询的分类

          1.连接查询:

          内连接:
          	相当于查询AB的交集部分
          外连接:
          		左外连接:
          			查询A的所有数据,同时拼接上B对应的数据
          		右外连接:
          			查询B的所有数据,同时拼接上A中对应的数据
          自连接:
          	表与自身连接查询
          	自连接必须给表取别名
          

          MySQL----多表查询,在这里插入图片描述,第9张

          2.子查询

          数据准备

          部门表:

          MySQL----多表查询,请添加图片描述,第10张

          create table dept (
              id int auto_increment primary key comment 'id',
              name varchar(50) not null comment '部门名称'
          ) comment '部门表';
          insert into dept (id, name)
          values (1, '研发部'),
                 (2, '市场部'),
                 (3, '财务部'),
                 (4, '销售部'),
                 (5, '总经办'),
                 (6, '人事部');
          

          员工表:

          MySQL----多表查询,请添加图片描述,第11张

          create table emp(
              id int auto_increment primary key ,
              name varchar(50) not null ,
              age int,
              job varchar(20) comment '职位',
              salary int ,
              entrydate date comment '入职时间',
              managerid int comment '直属领导id',
              dept_id int comment '所在部门id'
          ) comment '员工表';
          insert into emp
          values ( 1, '金庸', 66, '总裁', 20000, '2000-01-01', null, 5 ),
                 ( 2, '张无忌', 20, '项目经理', 12500, '2005-12-05', 1, 1 ),
                 ( 3, '杨晓', 33, '开发', 8400, '2000-11-03', 2, 1 ),
                 ( 4, '韦一笑', 48, '开发', 11000, '2002-02-05', 2, 1 ),
                 ( 5, '陈玉存', 43, '开发', 10500, '2004-09-07', 3, 1 ),
                 ( 6, '小昭', 19, '程序员鼓励师', 6600, '2004-10-12', 2, 1 ),
                 ( 7, '灭绝', 60, '财务总监', 8500, '2002-09-12', 1, 3 ),
                 ( 8, '周芷若', 19, '会计', 48000, '2006-06-02', 7, 3 ),
                 ( 9, '丁敏君', 23, '出纳', 5250, '2009-05-13', 7, 3 ),
                 ( 10, '赵敏', 20, '市场部总监', 12500, '2004-10-12', 1, 2 ),
                 ( 11, '鹿杖客', 56, '职员', 3750, '2006-10-03', 10, 2 ),
                 ( 12, '何碧文', 19, '职员', 3750, '2007-05-09', 10, 2 ),
                 ( 13, '东方白', 19, '职员', 5500, '2009-02-12', 10, 2 ),
                 ( 14, '张三丰', 88, '销售总监', 14000, '2004-10-12', 1, 4 ),
                 ( 15, '鱼梁洲', 38, '销售', 4600, '2004-10-12', 14, 4 ),
                 ( 16, '宋远桥', 40, '销售', 4600, '2004-10-12', 14, 4 ),
                 ( 17, '陈友谅', 42, null, 2000, '2011-10-12', 1, null );
          

          内连接

          语法:

          # 隐式内连接
          select 字段列表 from 表1,表2 where 条件;
          # 显示内连接
          select 字段列表 from 表1 [inner] join 表2 on 连接条件;
          

          内连接查询的是两张表交集的部分

          # 查询每一个员工的姓名及关联的部门的名称
          select emp.name, dept.name from emp, dept where emp.dept_id=dept.id;
          select emp.name, dept.name from emp inner join dept on emp.dept_id = dept.id;
          

          外连接

          语法:

          # 左外连接
          select 字段列表 from 表1 left [outer] join 表2 on 条件;
          # 右外连接
          select 字段列表 from 表1 right [outer] join 表2 on 条件;
          

          左外连接相当于查询表1的所有数据包含表1和表2交集的部分数据

          右外连接相当于查询表2的所有数据包含表1和表2交集部分的数据

          # 查询emp表的所有数据,和应于的部门信息(左)
          select emp.*, dept.* from emp left outer join dept on emp.dept_id = dept.id;
          # 查询dept表的所有数据,和对于的员工信息(右)
          select dept.*, emp.* from emp right outer join dept on emp.dept_id = dept.id;
          

          左外连接和右外连接可以进行相互转化

          自连接

          语法:

          select 字段列表 from 表a 别名a join 表a 别名b on 条件;
          

          自链接查询可以是内连接查询也可以是外连接查询

          # 查询员工及其所属领导的名字
          # 自连接可以看成两张一样的表进行连接查询
          select a.name, b.name from emp a join emp b on a.managerid=b.id;
          

          联合查询

          union、union all

          对于联合查询就是把多次查询的结果合并起来,形成一个新的查询结果集

          语法:

          select 字段列表 from 表a
          union [all]
          select 字段列表 from 表b
          
          # 将薪资低于5000的员工和年龄大于50的员工查询出来
          select * from emp where salary>5000
          union all
          select * from emp where age>50;
          
          # 没有all重复满足条件的只出现一次
          # 将薪资低于5000的员工和年龄大于50的员工查询出来
          select * from emp where salary>5000
          union
          select * from emp where age>50;
          

          对于联合查询的多张表的列数必须保持一致,字段类型也要保持一致

          union all会将全部的数据直接合并在一起,union会对合并之后的数据去重

          子查询

          概念:SQL语句中嵌套select语句为嵌套查询,又称子查询

          select * from 表1 where 字段=(select 字段 from 表2);

          子查询外的语句可以是insert、update、delete、select中的一个

          根据子查询的结构不同,分为:

          标量子查询:子查询的结果为单个值
          列子查询:子查询的结果为一列
          行子查询:子查询的结果为一行
          表子查询:子查询的结果为多行多列
          

          根据子查询的位置,分为:

          where之后
          from之后
          select之后
          

          标量子查询

          子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式,这种子查询称为标量子查询

          常用符号:=、<>、>、>=、<、<=

          # 根据销售部门的id查询员工信息
          # 先分开查询
          # 查询销售部门的id
          select id from dept where name='销售部'; #id为4
          # 查询销售部门中员工的信息
          select * from emp where dept_id=4;
          # 合并为一个查询
          select * from emp where dept_id=(select dept.id from dept where dept.name='销售部' );
          

          列子查询

          子查询的结果为一列(可以是多行)的,这种子查询为列子查询

          常用操作符:

          MySQL----多表查询,在这里插入图片描述,第12张

          # 列子查询
          # 查询销售部和市场部的所有员工信息
          # 查询销售部和市场部的id
          select id from dept where name='销售部' or name='市场部'; #id为2 4
          # 查询两个部门的所有员工
          select * from emp where dept_id in (2,4);
          # 合并
          select * from emp where dept_id in (select id from dept where name='销售部' or name='市场部');
          

          行子查询

          子查询返回的结果是一行(可以是多列),这种子查询为行子查询

          常用操作符:=、<>、in、not in

          # 查询与张无忌的薪资及直属领导相同的员工信息
          # 查询张无忌的薪资和直属领导
          select salary, managerid from emp where name='张无忌';
          # 查询与张无忌的薪资及直属领导相同的员工信息
          select * from emp where (salary,managerid)=(select salary, managerid from emp where name='张无忌');
          

          表子查询

          子查询的结果是多行多列这种查询为表子查询

          常用操作符:in

          # 查询与鹿杖客和宋远桥的职位和薪资相同的员工信息
          select * from emp where (job, salary) in ( select job, salary from emp where name in ('鹿杖客', '宋远桥'));
          

          表子查询的子表作为临时表

          # 查询入职日期是’2006-01-01‘之后的员工信息和部门信息
          # 先查询出入职在’2006-01-01‘之后员工的所有信息
          # 与部门表左连接
          select e.*, dept.* from (select * from emp where entrydate>'2006-01-01') e left outer join dept on e.dept_id=dept.id;
          

          多表查询案例

          MySQL----多表查询,在这里插入图片描述,第13张

          数据准备:

          create table salgrade (
              grade int,
              losal int comment '本薪资等级的最低界限',
              hisal int comment '最高界限'
          ) comment '薪资等级表';
          insert into salgrade values (1,0,3000);
          insert into salgrade values (2,3001,5000);
          insert into salgrade values (3,5001,8000);
          insert into salgrade values (4,8001,10000);
          insert into salgrade values (5,10001,15000);
          insert into salgrade values (6,15001,20000);
          insert into salgrade values (7,20001,25000);
          insert into salgrade values (8,025001,30000);
          

          1.查询员工的姓名,年龄,职位,部门信息(隐式内连接)

          select e.name, e.age, e.job, d.* 
          from emp e, dept d 
          where e.dept_id=d.id;
          

          2.查询年龄小于30的员工的姓名、年龄、职位、部门信息(显示内连接)

          select e.name,e.age,e.job,d.*
          from emp e
          inner join dept d on e.dept_id = d.id
          where e.age<30;
          

          3.查询拥有员工的部门id,部门名称

          select distinct d.id,d.name
          from emp e, dept d
          where d.id=e.dept_id;
          

          4.查询所有年龄大于40的员工,及其归属部门名称,如果员工没有分配部门也要显示

          select e.*,d.name
          from emp e
          left outer join dept d on e.dept_id = d.id
          where e.age>40;
          

          5.查询所有员工的工资等级

          select e.*,s.grade
          from emp e, salgrade s
          where e.salary between s.losal and s.hisal;
          

          6.查询研发部所有员工的信息即工资等级

          select e.*,s.grade
          from emp e,dept d,salgrade s
          where (e.dept_id=d.id) and (d.name='研发部') and (e.salary between s.losal and s.hisal);
          

          7.查询研发部员工的平均工资

          select avg(e.salary)
          from emp e, dept d
          where e.dept_id=d.id and d.name='研发部';
          

          8.查询工资比灭绝高的员工信息

          select *
          from emp
          where emp.salary > (
                                select e.salary
                                from emp e
                                where e.name='灭绝'
                                );
          

          9.查询比平均薪资高的员工信息

          select *
          from emp
          where salary> (
              select avg(e.salary)
              from emp e
              );
          

          10.查询低于本部门平均工资的员工信息

          select *
          from emp
          where emp.salary<(
              select avg(salary)
              from emp e
              where e.dept_id=emp.dept_id
              );
          

          11.查询所有部门信息,并统计部门的员工人数

          select d.*, (
              select count(*)
              from emp
              where emp.dept_id=d.id
              )
          from dept d;
          

          MySQL----多表查询,在这里插入图片描述,第14张