MySQL数据库查询之多表查询总结


Posted in MySQL onAugust 05, 2022

多表关系

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

表与表之间的联系:

1.一对多(多对一)

2.多对多

3.一对一

一对多(多对一)

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

MySQL数据库查询之多表查询总结

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

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

多对多

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

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

MySQL数据库查询之多表查询总结

一对一

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

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

MySQL数据库查询之多表查询总结

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

多表查询

概述:

从多张表中查询数据

笛卡尔积:

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

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

MySQL数据库查询之多表查询总结

dept表:

MySQL数据库查询之多表查询总结

emp表:

MySQL数据库查询之多表查询总结

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

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

MySQL数据库查询之多表查询总结

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

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

MySQL数据库查询之多表查询总结

多表查询的分类

1.连接查询:

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

MySQL数据库查询之多表查询总结

2.子查询

数据准备

部门表:

MySQL数据库查询之多表查询总结

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数据库查询之多表查询总结

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数据库查询之多表查询总结

# 列子查询
# 查询销售部和市场部的所有员工信息
# 查询销售部和市场部的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数据库查询之多表查询总结

数据准备:

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数据库查询之多表查询总结

总结

到此这篇关于MySQL数据库查询之多表查询的文章就介绍到这了,更多相关MySQL多表查询内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

MySQL 相关文章推荐
jdbc使用PreparedStatement批量插入数据的方法
Apr 27 MySQL
MySQL 重写查询语句的三种策略
May 10 MySQL
超详细教你怎么升级Mysql的版本
May 19 MySQL
MySQL 查询速度慢的原因
May 25 MySQL
详解MySQL多版本并发控制机制(MVCC)源码
Jun 23 MySQL
MySQL系列之九 mysql查询缓存及索引
Jul 02 MySQL
MySQL中的隐藏列的具体查看
Sep 04 MySQL
mysql中varchar类型的日期进行比较、排序等操作的实现
Nov 17 MySQL
MySQL读取JSON转换的方式
Mar 18 MySQL
浅谈MySQL中的六种日志
Mar 23 MySQL
MySQL8.0 Undo Tablespace管理详解
Jun 16 MySQL
MySQL数据库之内置函数和自定义函数 function
Jun 16 MySQL
分享很少见很有用的SQL功能CORRESPONDING
Aug 05 #MySQL
MySQL存储过程及语法详解
Aug 05 #MySQL
MySQL自定义函数及触发器
Aug 05 #MySQL
MySQL性能指标TPS+QPS+IOPS压测
Aug 05 #MySQL
Mysql中mvcc各场景理解应用
Aug 05 #MySQL
数据设计之权限的实现
一文解答什么是MySQL的回表
Aug 05 #MySQL
You might like
ThinkPHP设置禁止百度等搜索引擎转码(简单实用)
2016/02/15 PHP
php生成复杂验证码(倾斜,正弦干扰线,黏贴,旋转)
2018/03/12 PHP
php实现二叉树中和为某一值的路径方法
2018/10/14 PHP
参考:关于Javascript中实现暂停的几篇文章
2007/03/04 Javascript
javascript实现unicode和字符的互相转换
2007/07/18 Javascript
prototype与jquery下Ajax实现的差别
2009/09/13 Javascript
捕获浏览器关闭、刷新事件不同情况下的处理方法
2013/06/02 Javascript
使用js 设置url参数
2013/07/08 Javascript
js修改input的type属性问题探讨
2013/10/12 Javascript
Javascript基础教程之数组 array
2015/01/18 Javascript
jQuery实现下拉框选择图片功能实例
2015/08/08 Javascript
Three.js学习之正交投影照相机
2016/08/01 Javascript
Google 地图控件集详解及实例代码
2016/08/06 Javascript
js+css3实现旋转效果
2017/01/20 Javascript
validationEngine 表单验证插件使用实例代码
2017/06/15 Javascript
浅谈JS封闭函数、闭包、内置对象
2017/07/18 Javascript
使用vs code开发Nodejs程序的使用方法
2017/09/21 NodeJs
vue如何判断dom的class
2018/04/26 Javascript
ES6与CommonJS中的模块处理的区别
2018/06/13 Javascript
基于layPage插件实现两种分页方式浅析
2019/07/27 Javascript
Vue 用Vant实现时间选择器的示例代码
2019/10/25 Javascript
javascript执行上下文、变量对象实例分析
2020/04/25 Javascript
Python实现生成简单的Makefile文件代码示例
2015/03/10 Python
python数据处理实战(必看篇)
2017/06/11 Python
使用python实现knn算法
2017/12/20 Python
python替换字符串中的子串图文步骤
2019/06/19 Python
Python控制台输出时刷新当前行内容而不是输出新行的实现
2020/02/21 Python
解决paramiko执行命令超时的问题
2020/04/16 Python
Pandas将列表(List)转换为数据框(Dataframe)
2020/04/24 Python
html5实现九宫格抽奖可固定抽中某项奖品
2020/06/15 HTML / CSS
关于.NET, HTML的五个问题
2012/08/29 面试题
大学毕业生自我鉴定
2013/11/05 职场文书
打架检讨书500字
2014/01/29 职场文书
培训心得体会怎么写
2016/01/25 职场文书
python实现A*寻路算法
2021/06/13 Python
python绘制云雨图raincloud plot
2022/08/05 Python