MySQL-多表查询

 🎉欢迎您来到我的MySQL基础复习专栏

☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克🍹
✨博客主页:小小恶斯法克的博客
🎈该系列文章专栏:重拾MySQL
🍹文章作者技术和水平很有限,如果文中出现错误,希望大家能指正🙏
📜 感谢大家的关注! ❤️

目录

📣多表查询

📣多表查询概述 

📣笛卡尔积

📣如何消除无效的笛卡尔积

📣分类

📣内连接

 📣​​​​​​​外连接

📣自连接

 📣总结


📣多表查询

 多表关系

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

一对多 (多对一)

多对多

一对一

 一对多

案例: 部门 与 员工的关系

关系: 一个部门对应多个员工,一个员工对应一个部门

实现: 通常在多的一方建立外键,关联一的一方的主键 (左边为n,右边为1)

    

 多对多

案例: 学生 与 课程的关系

关系: 一个学生可以选修多门课程,一门课程也可以供多个学生选择

实现: 维护多对多的关系,需要建立第三张中间表,中间表至少包含两个外键,分别关联两方主键

 可以由下表看出,学生表和课程表是通过中间表取得关联

准备脚本:

create table student(id int auto_increment primary key comment '主键ID',name varchar(10) comment '姓名',no varchar(10) comment '学号'
) comment '学生表';insert into student values (null, '沈立聪', '2106030322'),(null, '李佳成', '2106030101'),(null, '陈治辉', '2106030407'),(null, '刘小金', '2106030608');create table course(id int auto_increment primary key comment '主键ID',name varchar(10) comment '课程名称'
) comment '课程表';insert into course values (null, 'math'), (null, 'chinese'), (null , 'english') , (null, 'good');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 '学生课程中间表';insert into student_course values (null,1,1),(null,1,2),(null,1,3),(null,2,2), (null,2,3),(null,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,'沈立聪',15,'1','12315468451'),
(null,'李佳成',25,'2','12341545641'),
(null,'陈治辉',25,'1','21234548421'),
(null,'刘小金',10,'1','12315315121');insert into tb_user_edu(id, degree, major, primaryschool, middleschool, university, userid) values
(null,'本科','舞蹈','a第一小学','e第一中学','家里蹲a学院',1),
(null,'硕士','表演','b第一小学','f第一中学','家里蹲b学院',2),
(null,'本科','英语','c第一小学','g第一中学','家里蹲c大学',3),
(null,'本科','应用数学','d第一小学','h第一中学','家里蹲d大学',4);

  

​​​​​​​📣多表查询概述 

概念:多表查询就是指从多张表中查询数据

删除之前 empcp, dept表的测试数据

执行如下脚本,创建empcp表与dept表并插入测试数据

-- 创建dept表,并插入数据
create table dept(id	int auto_increment comment 'ID' primary key,name varchar(50) not null comment '部门名称'
)comment '部门表';INSERT INTO dept (id, name) VALUES (1, '研发部'), (2, '市场部'),(3, '财务部'), (4, '销售部'), (5, '总经办'), (6, '人事部');-- 创建empcp表,并插入数据
create table empcp(id int auto_increment comment 'ID' primary key,name varchar(50) not null comment '姓名',age int comment '年龄',job varchar(20) comment '职位',salary int comment '薪资',entrydate date comment '入职时间',managerid int comment '直属领导ID',dept_id int comment '部门ID'
)comment '员工表';-- 添加外键
alter table empcp add constraint fk_empcp_dept_id foreign key (dept_id) references dept(id);INSERT INTO empcp (id, name, age, job,salary, entrydate, managerid, dept_id) VALUES
(1, 'a', 66, '总裁',20000, '2000-01-01', null,5),
(2, 'b', 20, '项目经理',12500, '2005-12-05', 1,1),
(3, 'c', 33, '开发', 8400,'2000-11-03', 2,1),
(4, 'd', 48, '开发',11000, '2002-02-05', 2,1),
(5, 'e', 43, '开发',10500, '2004-09-07', 3,1),
(6, 'f', 19, '程序员鼓励师',6600, '2004-10-12', 2,1),
(7, 'g', 60, '财务总监',8500, '2002-09-12', 1,3),
(8, 'h', 19, '会计',48000, '2006-06-02', 7,3),
(9, 'i', 23, '出纳',5250, '2009-05-13', 7,3),
(10, 'j', 20, '市场部总监',12500, '2004-10-12', 1,2),
(11, 'k', 56, '职员',3750, '2006-10-03', 10,2),
(12, 'l', 19, '职员',3750, '2007-05-09', 10,2),
(13, 'm', 19, '职员',5500, '2009-02-12', 10,2),
(14, 'n', 88, '销售总监',14000, '2004-10-12', 1,4),
(15, 'o', 38, '销售',4600, '2004-10-12', 14,4),
(16, 'p', 40, '销售',4600, '2004-10-12', 14,4),
(17, 'q', 42, null,2000, '2011-10-12', 1,null);

执行:

原来查询单表数据,执行的SQL形式为:select * from empcp;

那么我们要执行多表查询,就只需要使用逗号分隔多张表即可,代码如下

select * from empcp , dept ; 

执行:

此时,我们看到查询结果中包含了大量的结果集,总共102条记录,而这其实就是员工表emp所有的记录

17条与部门表dept所有记录6条的所有组合情况,这种现象称之为笛卡尔积。接下来,就来简单介绍下笛卡尔积。

📣笛卡尔积

笛卡尔积: 笛卡尔乘积是指在数学中,两个集合A集合 和  B集合的所有组合情况。

举个例子:

集合A={a,b}, B={0,1,2},笛卡尔积结果为:

A×B={(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}
B×A={(0, a), (0, b), (1, a), (1, b), (2, a), (2, b)} 

而在多表查询中,我们是需要消除无效的笛卡尔积的,只保留两张表关联部分的数据。

 如图我们只需要dept_id与dept.id相同的数据,即 dept_id = dept.id,其他对应关系不需要

📣如何消除无效的笛卡尔积

给多表查询加上连接查询条件就可以解决了

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

此时可以发现无效的笛卡尔积被清除了,但是我们有17个人,按逻辑应该有17条数据,那么第17条数据呢? 

实际上我们仔细观察到,第17条数据没有dept_id字段,所以在多表查询时,根据连接查询的条件并没有查询

​​​​​​​📣​​​​​​​分类

连接查询

内连接:相当于查询A、B交集部分数据

外连接:

        左外连接:查询左表所有数据,以及两张表交集部分数据

        右外连接:查询右表所有数据,以及两张表交集部分数据

自连接:当前表与自身的连接查询,自连接必须使用表别名

子查询

📣​​​​​​​内连接

​​​​​​​查询两张表之间交集的数据(也就是绿色部分的数据)

内连接的语法分为两种:

隐式内连接

SELECT 字段列表	FROM	表1 , 表2	WHERE	条件 ... ;

显式内连接

SELECT 字段列表	FROM	表1 [ INNER ] JOIN 表2 ON 连接条件 ... ;

案例:

查询每一个员工的姓名 , 及关联的部门的名称 (隐式内连接实现)

表结构: empcp , dept

连接条件: empcp.dept_id = dept.id  (其实这个连接条件就是用于消除无效的笛卡尔积的那个外键)

这里empcp.name,dept.name,前面加上表名,是通过表名来限定,是哪一个表的哪个字段

这里查询出来依旧是16条,因为有一个人是没有部门的,也就不属于两张表的交集部分,所以这条数据查询不到

select empcp.name 员工姓名 , dept.name 部门名  from empcp , dept  where empcp.dept_id = dept.id ; 

有时如果表名比较长,取名比较繁琐,我们就会起别名,通常在多表查询中我们都会起别名

注意:我们一旦给表起了别名之后,我们还能不能通过表名来限定字段,不可以,如果我们为表起了别名,此时我们就不能再通过表名来限定字段,此时只能够使用别名来指定字段。

因为对于DQL语句执行顺序,先执行的是from,执行完from,这表就已经起名为别名了,我们只能去使用别名了

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

执行: 

查询每一个员工的姓名 , 及关联的部门的名称 (显式内连接实现) --- INNER JOIN ... ON ...

表结构: empcp , dept

连接条件: empcp.dept_id = dept.id

select e.name, d.name from empcp e inner join dept d on e.dept_id = d.id;  -- 为每一张表起别名,简化SQL编写select e.name, d.name from empcp e join dept d on e.dept_id = d.id; --在显示内连接中inner关键字可以省略

表的别名:

①. tablea as 别名1 , tableb as 别名2 ;

②. tablea 别名1 , tableb 别名2 ;

 

 📣​​​​​​​外连接

外连接分为两种,分别是:左外连接 和 右外连接。

左外连接

SELECT 字段列表	FROM	表1 LEFT [ OUTER ] JOIN 表2 ON 条件 ... ;

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

 

右外连接

SELECT 字段列表	FROM	表1 RIGHT [ OUTER ] JOIN 表2 ON 条件 ... ;  --outer可有可无

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

案例:

查询empcp表的所有数据, 和对应的部门信息

由于需求中提到,要查询empcp的所有数据,因为内连接有一条数据查询不出来,17号它没有关联的数据,所以查询不出来,要查到所有数据是不能用内连接查询的,需要考虑使用外连接查询。 

表结构: empcp, dept

连接条件: empcp.dept_id = dept.id (empcp表的外键关联dept表的主键)

select e.*, d.name from empcp e left outer join dept d on e.dept_id = d.id; select e.*, d.name from empcp e left join dept d on e.dept_id = d.id;

 执行:

17条记录,第17条即使没有部门id,依然查询出,因为左外连接会完全包含左表数据

查询dept表的所有数据, 和对应的员工信息(右外连接)

由于需求中提到,要查询dept表的所有数据,所以是不能内连接查询的,需要考虑使用外连接查  询。

表结构: empcp, dept

连接条件: empcp.dept_id = dept.id

select d.*, e.* from empcp e right outer join dept d on e.dept_id = d.id; select d.*, e.* from dept d left outer join empcp e on e.dept_id = d.id; 
--此时左外会完全包含左表的数据,此时左表不就是dept表嘛,这就是左右外连接互换

执行:

人事部没有数据,依然可以查询出,因为右外连接会把表2的数据全部显示,右外连接完全包含右表

注意事项:

左外连接和右外连接是可以相互替换的,只需要调整在连接查询时SQL中,表结构的先后顺 序就可以了。而我们在日常开发使用时,更偏向于左外连接。

📣自连接

自己连接自己,也就是把一张表连接查询多次

SELECT 字段列表	FROM	表A	别名A	JOIN 表A	别名B	ON 条 件 ... ;

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

案例:

查询员工及其所属领导的名字

表结构: empcp

员工表是empcp这个我们知道,但是这个里面要查询的是所属领导的名字,在empcp中并没有去记录直属领导的是谁?但是empcp表中有一个字段managerid,指的就是所属领导的id,在企业中,领导是不是也是员工,所以这个managerid指代的就是当前表的主键,员工的id

例如这样的关系

id为1的managerid为null,说明他没有直属领导

id为2的人是id为3和4的直属领导,因为id3和4的人的managerid是2

此时涉及到的表结构只有一张表empcp表,所以我们的思路肯定是去查询empcp表,但是我们的单表查询是完不成这项问题的,我们要通过多表查询,连接empcp表两次,运用自连接

也就是把一张表看成两张表,一张员工表,一张领导表,用员工表的managerid关联领导表的id

select a.name as '员工' , b.name as '领导' from empcp a , empcp b where a.managerid = b.id;

执行:

查询所有员工 empcp表 及其领导的名字 empcp表 , 如果员工没有领导, 也需要查询出来

表结构: empcp a , empcp b

员工没有领导也要查询,意思就是这个员工的managerid是null我们也要把他查询出来,此时要用到外连接,因为内连接只查询两张表交集的部分,外连接才会完全包含左表或右表的数据,这里我们使用左外,一定一定看成两张表去做,a表是员工表,b表是领导表

select a.name '员工', b.name '领导' from empcp a left join empcp b on a.managerid = b.id;

注意事项:

在自连接查询中,必须要为表起别名,要不然我们不清楚所指定的条件、返回的字段,到底 是哪一张表的字段,谁的managerid=谁的id?对吧。

执行:


 📣总结

谢谢你这么好看还来看我!

   

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/237298.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Explain详解与索引最佳实践

听课问题(听完课自己查资料) type中常用类型详细解释 null <- system <- const <- er_ref <- ref <- range <- index <- all Explain 各列解释 EXPLAIN SELECT* FROMactorLEFT JOIN film_actor ON actor_id actor.id; 1. id 代表执行的先后顺序 比如…

ffmpeg[学习(四)](代码实现) 实现音频数据解码并且用SDL播放

0、作者杂谈 CSDN大多数都是落后的&#xff0c;要么是到处复制粘贴的&#xff0c;对于初学者我来说困惑了很久&#xff0c;大多数CSDN文章都是使用旧的API &#xff0c;已经被否决了&#xff0c;于是我读一些官方文档&#xff0c;和一些开源项目音视频的输出过程&#xff0c;写…

React Hooks中useState的介绍,并封装为useSetState函数的使用

useState 允许我们定义状态变量&#xff0c;并确保当这些状态变量的值发生变化时&#xff0c;页面会重新渲染。 useState 返回值 const [state, setState] useState(initialState);useState 返回一个长度为 2 的数组。通常&#xff0c;我们这样定义状态变量&#xff1a; co…

ActiveMQ反序列化RCE漏洞复现(CVE-2023-46604)

漏洞名称 Apache ActiveMQ OpenWire 协议反序列化命令执行漏洞 漏洞描述 Apache ActiveMQ 是美国阿帕奇&#xff08;Apache&#xff09;软件基金会所研发的一套开源的消息中间件&#xff0c;它支持Java消息服务、集群、Spring Framework等。 OpenWire协议在ActiveMQ中被用于…

C语言如何提高程序的可读性?

一、问题 可读性是评价程序质量的一个重要标准&#xff0c;直接影响到程序的修改和后期维护&#xff0c;那么如何提高程序的可读性呢? 二、解答 提高程序可读性可以从以下几方面来进行。 &#xff08;1&#xff09;C程序整体由函数构成的。 程序中&#xff0c;main()就是其中…

ArchVizPRO Interior Vol.8 URP

ArchVizPRO Interior Vol.8 URP是一个在URP中制作的建筑可视化项目。这是一个完全可导航的现代公寓,包括一个带开放式厨房的客厅、休息区、两间卧室和两间浴室。从头开始构建每一个细节,这个室内有130多件家具和道具、自定义着色器和4K纹理。所有家具和道具都非常详细,可以在…

使用 C++/WinRT 创作 API

如果 API 位于 Windows 命名空间中 这是你使用 Windows 运行时 API 最常见的情况。 对于元数据中定义的 Windows 命名空间中的每个类型&#xff0c;C/WinRT 都定义了 C 友好等效项&#xff08;称为投影类型 &#xff09;。 投影类型具有与 Windows 类型相同的完全限定名称&…

【.NET Core】Lazy<T> 实现延迟加载详解

【.NET Core】Lazy 实现延迟加载详解 文章目录 【.NET Core】Lazy<T> 实现延迟加载详解一、概述二、Lazy<T>是什么三、Lazy基本用法3.1 构造时使用默认的初始化方式3.2 构造时使用指定的委托初始化 四、Lazy.Value使用五、Lazy扩展用法5.1 实现延迟属性5.2 Lazy实现…

【LeetCode:30. 串联所有单词的子串 | 滑动窗口 + 哈希表】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

K8S后渗透横向节点与持久化隐蔽方式探索

前言 通常在红蓝对抗中&#xff0c;我们可能会通过各种方法如弱口令、sql注入、web应用漏洞导致的RCE等方法获得服务器的权限&#xff1b;在当前云原生迅猛发展的时代&#xff0c;这台服务器很可能是一个容器&#xff0c;在后续的后渗透由传统的提权变为容器逃逸&#xff0c;内…

【MySQL】导入导出SQL脚本及远程备份---超详细介绍

目录 前言&#xff1a; 一 navcat导入导出 1.1 导入 1.2 导出 二 mysqldump 导入导出 2.1 导入 2.2 导出 三 load data infile命令导入导出 3.1 导入 3.2 导出 四 远程备份 五 思维导图 前言&#xff1a; 随着当今企业发展&#xff0c;数据库的数据越来越多&…

POI:对Excel的基本写操作 整理1

首先导入相关依赖 <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --><!--xls(03)--><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.2</version></depend…

Java副本的概念

在Java中&#xff0c;"副本"&#xff08;copy&#xff09;一词可以用于描述不同的概念&#xff0c;具体取决于上下文。以下是两个常见的用法&#xff1a; 对象的副本&#xff1a;在Java中&#xff0c;当你创建一个对象并将其赋值给另一个变量时&#xff0c;实际上是创…

electron自定义窗口和右键菜单样式

前言 electron默认沿用系统UI&#xff0c;并没有提供很多接口供使用者定制样式&#xff0c;如果想要完全自定义的样式&#xff0c;目前我能想到的方案只能是通过前端自定义样式&#xff0c;然后通过进程通信来实现系统基础功能&#xff1a;最大/小化、关闭、拖动窗口等。 效果…

迈入AI智能时代!ChatGPT国内版免费AI助手工具 peropure·AI正式上线 一个想法写一首歌?这事AI还真能干!

号外&#xff01;前几天推荐的Peropure.Ai迎来升级&#xff0c;现已支持联网模式&#xff0c;回答更新更准&#xff0c;欢迎注册体验&#xff1a; https://sourl.cn/5T74Hu 相信很多人都有过这样的想法&#xff0c;有没有一首歌能表达自己此时此刻的心情&#xff1a; 当你在深…

xtu oj 1329 连分式

题目描述 连分式是形如下面的分式&#xff0c;已知a,b和迭代的次数n&#xff0c;求连分式的值。 输入 第一行是一个整数T(1≤T≤1000)&#xff0c;表示样例的个数。 每行一个样例&#xff0c;为a,b,n(1≤a,b,n≤9) 输出 每行输出一个样例的结果&#xff0c;使用x/y分式表达…

Go-安装与基础语法

TOC 1. Go 安装与环境变量 1.1 下载 需要从Go语言的官方网站下载适合你操作系统的Go语言安装包。Go语言支持多种操作系统&#xff0c;包括Windows、Linux和Mac OS。 对于Windows用户&#xff0c;下载.msi文件&#xff0c;然后双击该文件&#xff0c;按照提示进行安装即可。…

学习Qt笔记

前言&#xff1a; 学习笔记的内容来自B站up主阿西拜编程 《Qt6 C开发指南 》2023&#xff08;上册&#xff0c;完整版&#xff09;_哔哩哔哩_bilibili《Qt6 C开发指南 》2023&#xff08;上册&#xff0c;完整版&#xff09;共计84条视频&#xff0c;包括&#xff1a;00书籍介…

FreeRTOS系统配置

一、前言 在实际使用FreeRTOS 的时候我们时常需要根据自己需求来配置FreeRTOS&#xff0c;而且不同架构 的MCU在使用的时候配置也不同。FreeRTOS的系统配置文件为FreeRTOSConfig.h&#xff0c;在此配置文件中可以完成FreeRTOS的裁剪和配置&#xff0c;这是非常重要的一个文件&a…

git修改历史(非最新)提交信息

二、修改最近第二次或更早之前的commit信息 当前有三次提交&#xff0c;从近到远分别为1、2、3 以修改第2次提交为例&#xff08;从最新往前数&#xff09; 1、使用命令git rebase -i HEAD~2 按i进入编辑模式&#xff0c;将对应的pick改为edit&#xff0c;然后ctrlc退出。最…