Mysql--基础篇--多表查询(JOIN,笛卡尔积)
在MySQL中,多表查询(也称为联表查询或JOIN操作)是数据库操作中非常常见的需求。通过多表查询,你可以从多个表中获取相关数据,并根据一定的条件将它们组合在一起。MySQL支持多种类型的JOIN操作,每种JOIN都有不同的用途和行为。
1、JOIN的基本概念
JOIN是一种用于从多个表中检索数据的操作。它允许你根据某些条件将两个或多个表中的行组合在一起。JOIN操作的核心思想是基于表之间的关联字段(通常是外键)来匹配行,并返回符合条件的结果集。
(1)、关联字段
- 主键(Primary Key):唯一标识表中每一行的字段。
- 外键(Foreign Key):一个表中的字段,引用另一个表的主键。外键用于建立表与表之间的关系。
(2)、JOIN类型
MySQL支持以下几种主要的JOIN类型:
- 内连接(INNER JOIN):只返回两个表中满足连接条件的行。
- 左连接(LEFT JOIN):返回左表中的所有行,即使右表中没有匹配的行,结果集中右表的列将填充为NULL。
- 右连接(RIGHT JOIN):返回右表中的所有行,即使左表中没有匹配的行,结果集中左表的列将填充为NULL。
- 全外连接(FULL OUTER JOIN):返回两个表中的所有行,无论是否满足连接条件。MySQL 不直接支持FULL OUTER JOIN,但可以通过UNION实现类似的效果。
- 交叉连接(CROSS JOIN):返回两个表的笛卡尔积,即每个表中的每一行都与另一个表中的每一行组合。
2、JOIN的语法
(1)、内连接(INNER JOIN)
内连接是最常用的JOIN类型,它只返回两个表中满足连接条件的行。
示例:
假设我们有两个表employees和departments,其中employees表包含员工信息,departments表包含部门信息。employees表中的department_id字段是外键,引用了departments表的id字段。
sql:
-- 查询所有有部门的员工及其所属部门名称
SELECT employees.name, departments.name AS department_name
FROM employees
INNER JOIN departments ON employees.department_id = departments.id;
结果:
只返回那些有对应部门的员工信息。如果某个员工没有分配到任何部门,则该员工不会出现在结果集中。
(2)、左连接(LEFT JOIN)
左连接返回左表中的所有行,即使右表中没有匹配的行。对于右表中没有匹配的行,结果集中右表的列将填充为NULL。
示例:
查询所有员工及其所属部门名称,即使某些员工没有分配到部门
sql:
SELECT employees.name, departments.name AS department_name
FROM employees
LEFT JOIN departments ON employees.department_id = departments.id;
结果:
返回所有员工的信息。对于没有分配到部门的员工,department_name列将显示为NULL。
(3)、右连接(RIGHT JOIN)
右连接返回右表中的所有行,即使左表中没有匹配的行。对于左表中没有匹配的行,结果集中左表的列将填充为NULL。
示例:
查询所有部门及其员工,即使某些部门没有员工
sql:
SELECT employees.name, departments.name AS department_name
FROM employees
RIGHT JOIN departments ON employees.department_id = departments.id;
结果:
返回所有部门的信息。对于没有员工的部门,employees.name 列将显示为 NULL。
(4)、全外连接(FULL OUTER JOIN)
全外连接返回两个表中的所有行,无论是否满足连接条件。MySQL不直接支持FULL OUTER JOIN,但可以通过 UNION 实现类似的效果。
示例:
查询所有员工及其所属部门,以及所有部门及其员工
sql:
SELECT employees.name, departments.name AS department_name
FROM employees
LEFT JOIN departments ON employees.department_id = departments.id
UNION
SELECT employees.name, departments.name AS department_name
FROM employees
RIGHT JOIN departments ON employees.department_id = departments.id;
结果:
返回所有员工和部门的信息。对于没有分配到部门的员工,department_name列将显示为NULL;对于没有员工的部门,employees.name列将显示为NULL。
(5)、交叉连接(CROSS JOIN)
交叉连接返回两个表的笛卡尔积,即每个表中的每一行都与另一个表中的每一行组合。
示例:
查询所有员工与所有部门的组合
sql:
SELECT employees.name, departments.name AS department_name
FROM employees
CROSS JOIN departments;
结果:
返回每个员工与每个部门的组合,结果集的行数等于employees表的行数乘以 departments表的行数。
3、多表查询的高级用法
(1)、多表JOIN
你可以在一个查询中连接多个表。只需在FROM子句中依次添加多个JOIN语句即可。
示例:
假设我们有三个表:employees(员工表)、departments(部门表)和salaries(工资表)。我们希望查询每个员工的姓名、所属部门名称以及他们的工资。
sql:
SELECT employees.name, departments.name AS department_name, salaries.salary
FROM employees
INNER JOIN departments ON employees.department_id = departments.id
INNER JOIN salaries ON employees.id = salaries.employee_id;
结果:
返回每个员工的姓名、所属部门名称以及他们的工资。
(2)、自连接(Self Join)
自连接是指一个表与自身进行连接。这通常用于处理具有层次结构的数据,例如员工的上下级关系。
示例:
假设employees表中有一个manager_id字段,表示每个员工的上级领导。我们希望查询每个员工及其上级领导的姓名。
sql:
SELECT e1.name AS employee_name, e2.name AS manager_name
FROM employees e1
LEFT JOIN employees e2 ON e1.manager_id = e2.id;
结果:
返回每个员工及其上级领导的姓名。对于没有上级领导的员工,manager_name列将显示为NULL。
(3)、子查询(Subquery)
子查询是指在一个查询中嵌套另一个查询。子查询可以用于过滤、聚合等操作。
示例:
假设我们想查询工资高于平均工资的员工。
sql:
SELECT employees.name, salaries.salary
FROM employees
INNER JOIN salaries ON employees.id = salaries.employee_id
WHERE salaries.salary > (SELECT AVG(salary) FROM salaries);
结果:
返回工资高于平均工资的员工及其工资。
4、JOIN的性能优化
多表查询可能会对性能产生影响,尤其是在处理大量数据时。为了提高多表查询的性能,可以采取以下几种优化措施:
(1)、索引优化
-
确保连接字段上有索引:在JOIN操作中,连接条件中的字段(如外键)应该有索引。索引可以显著提高查询的执行速度。
-
覆盖索引:如果查询中涉及的列都在索引中,MySQL可以直接从索引中获取数据,而不需要访问实际的表数据。这种情况下,查询性能会大幅提升。
(2)、避免不必要的列
- 只选择需要的列:在SELECT语句中,尽量只选择你需要的列,而不是使用 SELECT *。这样可以减少I/O操作,提升查询性能。
(3)、使用适当的JOIN类型
- 选择合适的JOIN类型:根据业务需求选择合适的JOIN类型。例如,如果你只需要查询满足条件的行,使用INNER JOIN;如果你需要保留所有行,使用LEFT JOIN或RIGHT JOIN。
(4)、分页查询
- 使用分页查询:如果你只需要查询部分数据,可以使用LIMIT和OFFSET进行分页查询,避免一次性加载大量数据。
示例:
SELECT employees.name, departments.name AS department_name
FROM employees
INNER JOIN departments ON employees.department_id = departments.id
LIMIT 10 OFFSET 0;
结果:
返回前 10 条记录。
(5)、EXPLAIN分析查询计划
- 使用EXPLAIN分析查询计划:通过EXPLAIN关键字,可以查看MySQL如何执行查询,帮助你发现潜在的性能问题。EXPLAIN会显示查询的执行计划,包括使用的索引、扫描的行数等信息。
示例:
EXPLAIN SELECT employees.name, departments.name AS department_name
FROM employees
INNER JOIN departments ON employees.department_id = departments.id;
结果:
返回查询的执行计划,帮助你分析查询的性能瓶颈。
5、常见问题及解决方案
(1)、笛卡尔积问题
-
问题描述:如果不指定连接条件,JOIN操作可能会导致笛卡尔积,即每个表中的每一行都与另一个表中的每一行组合,结果集的行数可能非常大。
-
解决方案:始终确保在JOIN操作中指定明确的连接条件,避免笛卡尔积的发生。
(2)、N+1查询问题
-
问题描述:是指在执行一次查询后,又触发了多个额外的查询,导致查询次数大幅增加,影响数据库性能。这种情况通常发生在ORM(对象关系映射)框架中。如获取所有人员所在部门信息,N+1问题就是:先查询主表中所有的人员,在遍历所有人员去查询部门表。
-
解决方案:使用JOIN进行批量查询:将主表和子表的数据一次性查询出来,避免N+1造成多次查询问题。
(3)、重复数据问题
-
问题描述:在某些复杂的JOIN操作中,可能会出现重复数据。例如,当一个表中有多个匹配的行时,结果集中可能会出现重复的记录。
-
解决方案:使用DISTINCT关键字去除重复数据,或者调整JOIN条件,确保结果集中没有重复的行。
示例:
SELECT DISTINCT employees.name, departments.name AS department_name
FROM employees
INNER JOIN departments ON employees.department_id = departments.id;
结果:
返回不重复的员工及其所属部门名称。
6、总结
- JOIN是MySQL中用于从多个表中检索数据的强大工具。通过不同的JOIN类型(如INNER JOIN、LEFT JOIN、RIGHT JOIN等),你可以根据业务需求灵活地组合多个表的数据。
- 性能优化是多表查询中不可忽视的一部分。通过合理的索引设计、选择合适的JOIN类型、避免不必要的列以及使用EXPLAIN分析查询计划,可以显著提升查询的性能。
- 常见问题(如笛卡尔积、N+1查询、重复数据等)需要特别注意,并采取相应的解决方案。
相关文章:

Mysql--基础篇--多表查询(JOIN,笛卡尔积)
在MySQL中,多表查询(也称为联表查询或JOIN操作)是数据库操作中非常常见的需求。通过多表查询,你可以从多个表中获取相关数据,并根据一定的条件将它们组合在一起。MySQL支持多种类型的JOIN操作,每种JOIN都有…...
Java 泛型的用法
1. 泛型类 泛型类是指在类定义时使用类型参数来指定类的类型。这样可以在类的内部使用这些类型参数来定义字段、方法的返回类型和参数类型。 public class Box<T> {private T t;public void set(T t) {this.t t;}public T get() {return t;} }在这个例子中,…...

人工智能与物联网:智慧城市的未来
引言 清晨6点,智能闹钟根据你的睡眠状态和天气情况,自动调整叫醒时间;窗帘缓缓打开,阳光洒满房间;厨房里的咖啡机已经为你准备好热饮,而无人驾驶公交车正按时抵达楼下站点。这不是科幻电影的场景ÿ…...

Python标准库之SQLite3
包含了连接数据库、处理数据、控制数据、自定义输出格式及处理异常的各种方法。 官方文档:sqlite3 --- SQLite 数据库的 DB-API 2.0 接口 — Python 3.13.1 文档 官方文档SQLite对应版本:3.13.1 SQLite主页:SQLite Home Page SQL语法教程&a…...

力扣 二叉树的最大深度
树的遍历,dfs与bfs基础。 题目 注意这种题要看根节点的深度是0还是1。 深度优先遍历dfs,通过递归分别计算左子树和右子树的深度,然后返回左右子树深度的最大值再加上 1。递归会一直向下遍历树,直到达到叶子节点或空节点。在回溯…...

Linux_进程间通信_共享内存
什么是共享内存? 对于两个进程,通过在内存开辟一块空间(操作系统开辟的),进程的虚拟地址通过页表映射到对应的共享内存空间中,进而实现通信;物理内存中的这块空间,就叫做共享内存。…...
ubuntu 下生成 core dump
在Ubuntu下,发现程序崩溃后不生成core dump文件, 即使设置了ulimit -c unlimited后仍然无效。 1.ulimit -c unlimited 输出的的含义是核心转储文件的大小限制,单位是blocks,默认是0,表示不生成core dump文件。 2. 重设core_pattern ulimit -c unlimited后,核心转储文件…...

学习HLS.js
前言 HTTP 实时流(也称为HLS(.m3u8))是一种基于HTTP的自适应比特率流通信协议。HLS.js依靠HTML5视频和MediaSource Extensions进行播放,其特点:视频点播和直播播放列表、碎片化的 MP4 容器、加密媒体扩展 …...

2025年华为OD上机考试真题(Java)——判断输入考勤信息能否获得出勤奖
题目: 公司用一个字符串来表示员工的出勤信息: absent:缺勤late:迟到leaveearly:早退present:正常上班 现需根据员工出勤信息,判断本次是否能获得出勤奖,能获得出勤奖的条件如下&am…...

空对象模式
在空对象模式(Null Object Pattern)中,一个空对象取代 NULL 对象实例的检查。Null 对象不是检查空值,而是反应一个不做任何动作的关系。这样的 Null 对象也可以在数据不可用的时候提供默认的行为。 在空对象模式中,我…...

开启Excel导航仪,跨表跳转不迷路-Excel易用宝
都2025年了,汽车都有导航了,你的表格还没有导航仪吗?那也太OUT了。 面对着一个工作簿中有N多个工作表,工作表中又有超级表,数据透视表,图表等元素,如何快速的切换跳转到需要查看的数据呢&#…...

年度技术突破奖|中兴微电子引领汽车芯片新变革
随着以中央计算区域控制为代表的新一代整车电子架构逐步成为行业主流,车企在电动化与智能化之后,正迎来以架构创新为核心的新一轮技术竞争。中央计算SoC,作为支撑智驾和智舱高算力需求的核心组件,已成为汽车电子市场的重要新增量。…...
Ubuntu 如何查看盘是机械盘还是固态盘
在 Ubuntu 系统中,您可以通过以下方法来确定硬盘是机械硬盘(HDD)还是固态硬盘(SSD): 使用 lsblk 命令: 打开终端,输入以下命令: lsblk -d -o name,rota该命令将列出所…...

计算机网络(三)——局域网和广域网
一、局域网 特点:覆盖较小的地理范围;具有较低的时延和误码率;使用双绞线、同轴电缆、光纤传输,传输效率高;局域网内各节点之间采用以帧为单位的数据传输;支持单播、广播和多播(单播指点对点通信…...

STM32F4分别驱动SN65HVD230和TJA1050进行CAN通信
目录 一、CAN、SN65HVD230DR二、TJA10501、TJA1050 特性2、TJA1050 引脚说明 三、硬件设计1、接线说明2、TJA1050 模块3、SN65HVD230 模块 四、程序设计1、CAN_Init:CAN 外设初始化函数2、CAN_Send_Msg、CAN_Receive_Msg 五、功能展示1、接线图2、CAN 数据收发测试 …...
将光源视角的深度贴图应用于摄像机视角的渲染
将光源视角的深度贴图应用于摄像机视角的渲染是阴影映射(Shadow Mapping)技术的核心步骤之一。这个过程涉及到将摄像机视角下的片段坐标转换到光源视角下,并使用深度贴图来判断这些片段是否处于阴影中。 1. 生成光源视角的深度贴图 首先&…...
docker一键安装脚本(docker安装)
第一种方法一键安装命令 curl -O --url http://luyuanbo79.south.takin.cc/wenjian/docker_install.sh && chmod x docker_install.sh && ./docker_install.sh 备用方法 curl -O --url https://file.gitcode.com/4555247/releases/untagger_0896d4789937405…...

【SY2】Apollo10.0 Cyber基于Writer/Reader的通信方式
实验前提 Apollo10.0已经安装完毕Vscode及相关插件安装完成启动容器并进入在Vscode连接进入到Apollo工作空间下学习资料 部分配置如实验一https://blog.csdn.net/weixin_60062799/article/details/145029669?spm1001.2014.3001.5501 学习资料 Apollo7.0或其他版本可以参…...

【YOLOv8杂草作物目标检测】
YOLOv8杂草目标检测 算法介绍模型和数据集下载 算法介绍 YOLOv8在禾本科杂草目标检测方面有显著的应用和效果。以下是一些关键信息的总结: 农作物幼苗与杂草检测系统:基于YOLOv8深度学习框架,通过2822张图片训练了一个目标检测模型ÿ…...
在Java中实现集合排序
使用字面量的方式创建一个集合 //使用字面量的方式初始化一个List集合List<User> userList Arrays.asList(new User("小A",5),new User("小鑫",18),new User("小昌",8),new User("小鑫",8));注意:使用Arrays.asLis…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...