131.【MySQL_基础篇】(四)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 131.【MySQL_基础篇】

(五)、多表查询

1.多表关系

(1).多表查询概述

项目开发中,再进行数据表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,基本上分为:

  1. 一对一
  2. 多对多
  3. 一对多(多对一)
(2).一对多 (多对一)关系

这种关系最典型的列子就是 员工和部门的关系。员工为N 部门为1。

这种我们通常在从表(员工表)也就是员工表创建一个外键,与主表(部门表)进行联系。

(3).多对多关系

这种关系最典型的列子就是 学生与课程的关系。一个学生可以选择多门课程,一门课程可以供多各学生选择。

这种我们需要建立第三张表(中间表)并包括两个外键,第一个外键需要与学生表进行关联,另一张表需要和课程表进行关联。

建立 学生表+课程表+中间表

create table student(
    id int auto_increment primary key comment '主键ID',
    name varchar(10) comment '姓名',
    no varchar(10) comment '学号'
) comment '学生表' charset=utf8;
insert into student values (null, '黛绮丝', '2000100101'),(null, '谢逊','2000100102'),(null, '殷天正', '2000100103'),(null, '韦一笑', '2000100104') ;
create table course(
    id int auto_increment primary key comment '主键ID',
    name varchar(10) comment '课程名称'
) comment '课程表' charset=utf8;
insert into course values (null, 'Java'), (null, 'PHP'), (null , 'MySQL') ,(null, 'Hadoop');
create table student_course(
    id int auto_increment comment '主键' primary key,
    studentid int not null comment '学生ID',
    courseid int not null comment '课程ID',
    constraint fk_courseid foreign key (courseid) references course (id),
    constraint fk_studentid foreign key (studentid) references student (id)
)comment '学生课程中间表' charset=utf8;
insert into student_course values (null,1,1),(null,1,2),(null,1,3),(null,2,2),(null,2,3);
(4)一对一关系

这种关系最典型的列子就是 用户与用户详情的关系。

一对一关系,多用于单表拆分,将一张表的基础字段放在一张表中,其他详情字段放在另一张表中,以提升操作效率。

这种关系我们需要在 任意一方假如外键,关联另外一方的主键,并且设置外键为唯一的(unique)

create table tb_user(
id int auto_increment primary key comment '主键ID',
name varchar(10) comment '姓名',
age int comment '年龄',
gender char(1) comment '1: 男 , 2: 女',
phone char(11) comment '手机号'
) comment '用户基本信息表';
create table tb_user_edu(
id int auto_increment primary key comment '主键ID',
degree varchar(20) comment '学历',
major varchar(50) comment '专业',
primaryschool varchar(50) comment '小学',
middleschool varchar(50) comment '中学',
university varchar(50) comment '大学',
userid int unique comment '用户ID',
constraint fk_userid foreign key (userid) references tb_user(id)
) comment '用户教育信息表';
insert into tb_user(id, name, age, gender, phone) values
(null,'黄渤',45,'1','18800001111'),
(null,'冰冰',35,'2','18800002222'),
(null,'码云',55,'1','18800008888'),
(null,'李彦宏',50,'1','18800009999');
insert into tb_user_edu(id, degree, major, primaryschool, middleschool,
university, userid) values
(null,'本科','舞蹈','静安区第一小学','静安区第一中学','北京舞蹈学院',1),
(null,'硕士','表演','朝阳区第一小学','朝阳区第一中学','北京电影学院',2),
(null,'本科','英语','杭州市第一小学','杭州市第一中学','杭州师范大学',3),
(null,'本科','应用数学','阳泉第一小学','阳泉区第一中学','清华大学',4);

2.多表查询概述

(1).笛卡尔积效应

笛卡尔积时指在数学中,两个集合A集合和B集合的所有组合情况(排列组合)。(在多表查询时,需要消除无效的笛卡尔积)

-- 多表查询,会发现出现笛卡尔积效应
select *from emp,dept;

(2).消除笛卡尔积效应

消除笛卡尔积效应的实质就是 消除掉不符合条件的排列组合数据。

-- 消除无效的笛卡尔积
select *from emp,dept where emp.dept_id=dept.id;

3.多表查询分类

(1).连接查询
  1. 内连接: 相当于查询A、B交集部分数据
  2. 外连接:
  • 左外连接: 查询左表所有数据,以及两张表交集部分数据
  • 右外连接:查询右表所有数据,以及两张表交集部分数据
  1. 自连接: 当前表与自身的连接查询,自连接必须使用表别名
(2).子查询

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

select *from 表1 where column1=(select column1 from 表2)

子查询外部的语句可以是 insert/update/delete/select的任何一个。

4.连接查询-内连接 (两张表交集部分) ⭐

(1).隐式内连接语法
selec 字段列表 from 表1,表2 where 条件...
(2).显示内连接语法
select 字段列表 from 表1 [inner] join 表2 on 连接条件...;
(3).隐式内连接和显示内联接测试
  1. 隐式内连接 查询部门员工和对应部门
-- 隐式内连接使用where进行判断
select emp.`name`,dept.name  from emp,dept on emp.dept_id=dept.id;
-- 隐式内连接起别名,起玩别名之后只能用别名操作了
select ep.`name`,dt.name  from emp as ep,dept as dt on ep.dept_id=dt.id;

  1. 显示内连接查询部门员工
-- 显示内连接
select emp.`name`,dept.name from emp inner join dept where emp.dept_id=dept.id;
-- 显示内连接 可省略inner
select emp.`name`,dept.name from emp inner join dept where emp.dept_id=dept.id;

5.连接查询-外连接 (查询某张表的全部数据和交集部分)

相当于查询 left 或 right 左侧的第一个表的全部数据。

(1).外连接查询语法
  1. 左外连接

这里相当于查询表1 的所有数据和表一与表二的交集

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

这里相当于查询表2 的所有数据和表一与表二的交集

select 字段列表 from 表1 right [outer] join 表2 on 条件;
(2).左外连接测试

关键字 left

-- 左外连接演示
-- 1.查询emp表的所有数据,和对应的部门信息(左外连接)
select * from emp left join dept on emp.dept_id=dept.id;
-- 2.查询emp表的所有数据,和对应的部门信息(左外连接) 起别名
select *from emp as ep left join dept as dt on ep.dept_id=dt.id; 

(3).右外连接测试

关键字 right

-- 1.查询dept表的所有数据,和对应的员工信息
select dept.*,emp.`name` from emp right join dept on emp.dept_id=dept.id;

6.连接查询-自连接 (可交集、可单独) ⭐

子连接查询语法,一定要给表起别名。

(1).自连接查询语法
select 字段列表 from 表A 别名A join 表A 别名B on 条件...;

自连接查询,可以是内连接查询,也可以是外连接查询。

(2).自连接测试
  1. 查询员工 及其 所属领导的名字

不管是什么连接都是经历了 排列组合 实现的数据查询

-- 自连接
-- 1.查询员工 及其 所属领导的名字, 这里的ep_1相当于员工表,ep_2相当于领导表。 利用员工表的领导id 找 员工表的id
select ep_1.`name`,ep_2.`name` from emp ep_1 join emp ep_2 on ep_1.managerid=ep_2.id;

  1. 查询所有员工 emp 及其 领导的名字emp,如果员工没有领导,也需要查询出来。
-- 查询所有员工 emp 及其 领导的名字emp,如果员工没有领导,也需要查询出来
select ep_1.`name`,ep_2.`name` from emp ep_1 left join emp ep_2 on ep_1.managerid=ep_2.id;

7.联合查询-union,union all

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

(1).联合查询的语法
select 字段列表 from 表A...
union [all]
select 字段列表 from 表B...
(2).联合查询示列
  1. 查询出所有满足的->不去重
-- 将薪资低于5000的员工,和年龄大于50岁的员工全部查询出来
select *from emp WHERE salary<5000 
union all #⭐
select *from emp WHERE age>50;

  1. 查询出所有满足的->去重
-- 将薪资低于5000的员工,和年龄大于50岁的员工全部查询出来  (去重)
select *from emp WHERE salary<5000 
union   # ⭐
select *from emp WHERE age>50;

注意:

  1. 对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致。
  2. union all会将全部的数据直接合并在一起,union会对合并之后的数据进行去重的操作。

8.子查询 (嵌套查询) ⭐

(1).子查询的基本语法

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

select *from 表1 where column1=(select column1 from 表2)
• 1

子查询外部的语句可以是 insert/update/delete/select的任何一个。

(2).子查询的分类

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

  1. 标量子查询(子查询结果为单个值)
  2. 列子查询(子查询结果为一列)
  3. 行字查询(子查询结果为一行)
  4. 表子查询(子查询结果为多行多列)

根据子查询位置,分为:where之后、from之后、select之后。

9.子查询-标量子查询 (返回结果是一个值)

(1).标量子查询

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

常用的操作符: <> = > >= < <=

(2).标量子查询示列

1..查询销售部的所有员工

-- 标量子查询
-- 1.查询销售部的所有员工信息
    -- 1.1先查找销售部的id
select  id from dept where `name`='销售部'
    -- 1.2再查找这个数据
select *from emp where emp.dept_id=4;
-- 完整写法
select *from emp where emp.dept_id= (select  id from dept where `name`='销售部');

2.查询在房东白入职之后的员工信息

-- 查询在方东白入职之后的员工信息
select entrydate from emp where name ='方东白';
select *from emp where entrydate>'2009-02-12';
-- 完整写法
select *from emp where entrydate>(select entrydate from emp where name ='方东白');

10.子查询-列子查询 (单列但可多行)

返回结构是一列数据 比如: 所有查询所有员工的id。 也就是一行数据里面的一个字段,但是可以是多行的同一字段。

(1).列子查询

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

常用的操作符: IN、NOT IN、ANY、SOME、ALL。

  1. IN : 在指定的集合范围之内,多选一。
  2. NOT IN: 不在指定的集合范围之内。
  3. ANY: 子查询返回列表,有任意一个满足即可。
  4. SOME: 与ANY等同,使用SOME的地方都可以使用ANY。
  5. ALL:子查询返回列表的所有值都必须满足。
(2).列子查询示列

1.查询销售部和市场部的所有员工

-- 列子查询
-- 1.查询销售部和市场部的所有员工
select id from dept where dept.`name` in ('市场部','销售部');
select *from emp where emp.dept_id in (2,4);
select *from emp where emp.dept_id in (select id from dept where dept.`name` in ('市场部','销售部'));

2.查询比财务部所有人工资都高的员工信息

-- 2.查询比财务部所有人工资都高的员工
第一种:使用聚合函数
-- 2.1 首先查询财务部的部门id 
select id from dept where dept.`name`='财务部'
-- 2.2然后聚合函数查询财务部的最高工资
select max(emp.salary) from emp where emp.dept_id=(select id from dept where dept.`name`='财务部')
-- 2.3 查询信息
select *from emp where emp.salary >= (select max(emp.salary) from emp where emp.dept_id=(select id from dept where dept.`name`='财务部')); 
第二种:使用列子查询
select *from emp where emp.salary  >= all(select emp.salary from emp where emp.dept_id=(select id from dept where dept.`name`='财务部')); 

3.查询比开发部任何一人工资低的员工信息

-- 3. 查询比研发部其中任意一人工资高的员工信息
第一种: 使用聚合函数
select dept.id from dept where dept.`name`='研发部';
select min(emp.salary) from emp where emp.dept_id = (select dept.id from dept where dept.`name`='研发部');
select *from emp where emp.salary >=(select min(emp.salary) from emp where emp.dept_id = (select dept.id from dept where dept.`name`='研发部'));
第二种:使用列子查询 (some、any)
select *from emp where emp.salary >= some(select emp.salary from emp where emp.dept_id = (select dept.id from dept where dept.`name`='研发部'));

11.子查询-行子查询 (单行但可多列)

返回的结果是一行,比如说查询 和 张无忌的薪资结构相同且领导相同的员工信息。薪资结构和领导都是张无忌一行的数据,一行数据多列字段。

(1).行子查询

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

(2).行子查询示列

1.查询与 张无忌的薪资结构 及 直属领导 相同的员工信息。查询的是张无忌一个

-- 行子查询
-- 1.查询与 张无忌的薪资结构 及 直属领导 相同的员工信息
select salary '薪资结构',managerid '管理者' from emp where emp.`name`='张无忌';
select *from emp where (emp.salary,emp.managerid) =(12500,1);
select *from emp where (emp.salary,emp.managerid) =(select salary '薪资结构',managerid '管理者' from emp where emp.`name`='张无忌');

12.子查询-表子查询 (多行且多列)

比如: 两行分别是 鹿杖客 宋远桥 这两行,两列 分别是 薪资结构和职位。

(1).表子查询

子查询返回的结果是 多行多列,这种子查询称为表子查询。

(2).表子查询示列

1.1.查询与 鹿杖客 宋远桥 的职位和薪资相同的员工信息

-- 表子查询
-- 1.查询与 鹿杖客 宋远桥 的职位和薪资相同的员工信息
select emp.job,emp.salary from emp where emp.`name` in ('鹿杖客','宋远桥');
-- 这里放in 表示要么一起满足这一行数据,要么一起满足下一行数据
select *from emp where (emp.job,emp.salary) in (select emp.job,emp.salary from emp where emp.`name` in ('鹿杖客','宋远桥'));

2.查询入职日期是 2006-01-01 之后的员工信息,及其部门信息

-- 2. 查询入职日期是 2006-01-01 之后的员工信息,及其部门信息
# 这个方法查询不完整,只查询到了交集,而要求我们查询一张表的全部信息
select *from emp,dept where emp.entrydate > '2006-01-01' and emp.dept_id=dept.id;  
select *from (select * from emp where emp.entrydate> '2006-01-01') as emp_a left join dept on emp_a.dept_id=dept.id;

注意: 我们新派生一张表的时候,我们要给这个新派生的表起别名,否则会报错。

起别名之后:

-- 1.查询员工的姓名,年龄、职位、部门信息 (隐式内连接)
select emp.`name`,emp.age,emp.job,dept.id from emp,dept where emp.dept_id = dept.id;
-- 2.查询年龄小于30岁的员工的姓名,年龄,职位,部门信息(显示内连接)
        #这里一定要使用where,如果使用and的话显示内连接会有效,但是外连接就会无效。
select *from emp join dept on emp.dept_id=dept.id where emp.age>30;
-- 3.查询拥有员工的部门ID、部门名称  (交集)
select DISTINCT dept.id,dept.`name` from dept join emp on dept.id=emp.dept_id;
--  4.查询所有年龄大于40岁的员工,及其归属的部门名称;如果没有分配部门,也需要展示出来 (左外连接)
      #这里千万不要使用and,如果使用and,外连接将会失效
select emp.`name`,dept.`name` from emp left join dept on emp.dept_id = dept.id where emp.age>40;
-- 5.查询所有员工的工资等级 : 员工表和薪资等级表是没有外键关联(直接在笛卡尔积中赛选了)  (隐式内连接)
select  emp.`name`,emp.salary,salgrade.grade from emp,salgrade where emp.salary>=salgrade.losal and emp.salary<=salgrade.hisal;
-- 6.查询 研发部 所有员工的信息及工资等级 (隐式内连接)
    select emp.`name`,emp.salary,dept.`name`,salgrade.grade from emp,salgrade join dept on dept.id=(select id from dept where dept.name='研发部') where emp.salary>=salgrade.losal and emp.salary<=salgrade.hisal;
-- 7.查询研发部 员工的平均薪资 (隐式内连接)
  select avg(emp.salary) from emp  join dept on dept.id=emp.dept_id where dept.id=(select id  from dept where dept.name='研发部');
-- 8. 查询工资比 灭绝 高的员工信息 (联表)
  select * from emp where  emp.salary >(select salary from emp where emp.`name`='灭绝');
-- 9.查询比平均薪资高的员工信息 (联表)
    select *from emp where emp.salary>(select avg(emp.salary) from emp);
-- 10.查询低于本部门平均工资的员工信息  (自连接)
    select * from emp e2 where e2.salary<(select avg(e1.salary) from emp e1 where e1.dept_id =e2.dept_id);
-- 11.查询所有的部门信息,并统计部门的员工人数 (分组)
    select count(*),dept.`name` from emp,dept where dept.id=emp.dept_id GROUP BY emp.dept_id;
-- 12.查询所有学生的选课情况,展示出学生名称、学号、课程名称。
select *from student,course where (student.id,course.id) in (select student_course.studentid,student_course.courseid from student_course)

注意:

  1. on后面的是联查条件,where是非联查条件。非联查条件不能用on;联查条件不能用where。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
12月前
|
数据采集 自然语言处理 文字识别
92页的llama 3.1技术报告,我替你们啃下来了
作者花了半个月时间,认真读完了llama 3.1技术报告,并总结成本文,希望能帮到对这个感兴趣的小伙伴们。
92页的llama 3.1技术报告,我替你们啃下来了
|
传感器 存储 Ubuntu
一步一步学会蓝牙开发之 ESP-IDF GATT Server 示例解析
学习蓝牙的 GATT 开发,我们从示例代码,一段代码一段代码进行详细分析说明
2769 1
一步一步学会蓝牙开发之 ESP-IDF GATT Server 示例解析
|
缓存 运维 关系型数据库
数据库容灾 | MySQL MGR与阿里云PolarDB-X Paxos的深度对比
经过深入的技术剖析与性能对比,PolarDB-X DN凭借其自研的X-Paxos协议和一系列优化设计,在性能、正确性、可用性及资源开销等方面展现出对MySQL MGR的多项优势,但MGR在MySQL生态体系内也占据重要地位,但需要考虑备库宕机抖动、跨机房容灾性能波动、稳定性等各种情况,因此如果想用好MGR,必须配备专业的技术和运维团队的支持。 在面对大规模、高并发、高可用性需求时,PolarDB-X存储引擎以其独特的技术优势和优异的性能表现,相比于MGR在开箱即用的场景下,PolarDB-X基于DN的集中式(标准版)在功能和性能都做到了很好的平衡,成为了极具竞争力的数据库解决方案。
|
文字识别 小程序 数据安全/隐私保护
9款文字识别(OCR)工具推荐!涵盖移动端、网页端、PC端,满足您的所有需求!
9款文字识别(OCR)工具推荐!涵盖移动端、网页端、PC端,满足您的所有需求!
2488 0
|
小程序 JavaScript Java
基于微信小程序的加油站服务管理系统设计与实现(源码+lw+部署文档+讲解等)
基于微信小程序的加油站服务管理系统设计与实现(源码+lw+部署文档+讲解等)
309 0
|
网络协议 安全
干货|不出网上线CS的各种姿势(三)
干货|不出网上线CS的各种姿势
497 0
|
JSON 小程序 前端开发
微信小程序开发—入门到跑路(二)
微信小程序开发—入门到跑路(二)
186 0
|
消息中间件 存储 RocketMQ
即时通讯技术文集(第20期):IM架构设计技术文章(Part3) [共14篇]
为了更好地分类阅读 52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第20 期。
167 0
|
机器学习/深度学习 算法 C语言
【数据结构与算法】时间复杂度与空间复杂度(上)
【数据结构与算法】时间复杂度与空间复杂度
117 0
|
前端开发 测试技术 数据库
【Servlet】规范项目结构|基于Mysql+JDBC+Servlet 制作简易网页|实现登录、添加、删除、显示的功能(下)
【Servlet】规范项目结构|基于Mysql+JDBC+Servlet 制作简易网页|实现登录、添加、删除、显示的功能
160 0