当前位置: 首页 > article >正文

09.MySQL内外连接

09.MySQL内外连接

文章目录

MySQL内外连接
内连接
外连接
左外连接
右外连接
简单案例


MySQL内外连接

在数据库操作中,表的连接是一个非常重要的概念。简单来说,连接就是将两个或多个表中的数据按照某种规则结合起来,从而获取我们所需要的信息。而在实际开发中,最常用的两种连接方式是内连接外连接

那么,这两种连接到底有什么区别呢?又分别适用于哪些场景呢?

内连接

先从内连接说起。顾名思义,内连接(INNER JOIN)就是只返回两个表中满足连接条件的数据。也就是说,只有当左表和右表都存在匹配的数据时,才会出现在结果集中。

那具体怎么用呢?其实语法也不复杂:

SELECT ... FROM t1 INNER JOIN t2 ON 连接条件 [INNER JOIN t3 ON 连接条件] ... AND 其他条件;

其中,大写的 SELECTFROMINNER JOINON 等都是 SQL 的关键字;而 [ ] 中的内容则是可选的,比如你可以根据需要添加更多的连接条件或者其他筛选条件。

举个例子吧,假设我们现在有两张表:一张员工表,记录了员工的基本信息,另一张部门表,记录了部门的编号和名称。现在我们要查询员工 “SMITH” 的名字和他的部门名称。

按照复合查询的做法,我们可能会先对两张表做笛卡尔积,然后在 WHERE 子句中指定筛选条件:员工的部门编号等于部门表的部门编号,并且员工姓名是 “SMITH”。但其实,这种写法本质上就是内连接,只不过标准的写法更直观一些:

SELECT ename, dname
FROM emp INNER JOIN dept ON emp.deptno = dept.deptno
AND ename = 'SMITH';

这样写的好处是逻辑更清晰,也更容易维护。

外连接

说完内连接,咱们再来看看外连接。外连接和内连接最大的区别在于:外连接可以返回不满足连接条件的行,而内连接不行。

外连接又分为左外连接(LEFT JOIN)和右外连接(RIGHT JOIN)。简单来说,左外连接会返回左表中的所有行,即使右表中没有匹配的数据;而右外连接则相反,会返回右表中的所有行。

左外连接

假设我们现在有一张学生表和一张成绩表。学生表记录了学生的学号和姓名,成绩表记录了学生的学号和考试成绩。现在有个需求:查询所有学生的成绩,即使这个学生没有成绩,也要显示他的个人信息

如果直接用内连接的话,那些没有成绩的学生信息就查不出来。这时候就得用左外连接了:

SELECT student.name, score.score
FROM student LEFT JOIN score ON student.id = score.id;

这样,即使某个学生的学号在成绩表中找不到匹配记录,他的姓名依然会出现在结果中,而对应的成绩字段则会显示为 NULL

右外连接

右外连接的使用场景和左外连接类似,只不过方向相反。比如,如果我们想查询所有的成绩记录,即使某个成绩对应的学号在学生表中不存在,也可以用右外连接:

SELECT student.name, score.score
FROM student RIGHT JOIN score ON student.id = score.id;

这时候,成绩表中的所有记录都会被保留,而学生表中没有匹配的字段会显示为 NULL

简单案例

为了更好地理解这些连接方式的区别,咱们再来看一个实际案例。

需求:列出所有部门的名称,以及这些部门的员工信息(包括没有员工的部门)

这里的关键是:即使某个部门没有员工,也要显示出来。这时候,内连接显然不够用了,因为内连接只会显示满足连接条件的记录。所以,我们需要用外连接。

假设部门表在左边,员工表在右边,我们可以这样写:

SELECT dept.dname, emp.ename
FROM dept LEFT JOIN emp ON dept.deptno = emp.deptno;

这样,所有部门名称都会被列出,而没有员工的部门对应的 ename 字段会是 NULL

当然,如果你想用右外连接实现同样的效果,也可以把部门表放在右边:

SELECT dept.dname, emp.ename
FROM emp RIGHT JOIN dept ON dept.deptno = emp.deptno;

结果是一样的,只是写法不同罢了。


内连接

内连接的核心思想是“只保留有交集的数据”。换句话说,如果一张表的某条记录在另一张表中找不到匹配项,这条记录就不会出现在最终结果里。

举个生活中的例子:假设你有一个朋友列表,还有一个聚会的签到表。如果你想查哪些朋友参加了聚会,就可以用内连接,把朋友列表和签到表按名字关联起来。这样,结果里只会包含既在朋友列表里、又在签到表里的名字。

再回到数据库层面。内连接的语法结构其实挺固定的,核心就是 INNER JOIN ... ON ...。比如,如果我们想查询每个员工的姓名和他们所在部门的名称,就可以这样写:

SELECT emp.ename, dept.dname
FROM emp INNER JOIN dept ON emp.deptno = dept.deptno;

这里的关键是 ON emp.deptno = dept.deptno,它指定了两张表的关联条件。只有当员工的部门编号和部门表的部门编号一致时,这两条记录才会被合并成一条结果。

不过,有时候我们还需要加一些额外的筛选条件。比如,只想查某个特定部门的员工信息,这时候就可以在 AND 后面加条件:

SELECT emp.ename, dept.dname
FROM emp INNER JOIN dept ON emp.deptno = dept.deptno
AND dept.dname = 'SALES';

这样,结果就只会包含销售部的员工了。

内连接的本质

从底层原理来看,内连接其实就是对两个表进行笛卡尔积之后,再通过连接条件过滤出有效的组合。比如,如果员工表有 10 条记录,部门表有 5 条记录,它们的笛卡尔积就是 50 条记录。然后,数据库会根据 emp.deptno = dept.deptno 这个条件筛选出符合条件的数据。

不过,虽然内连接的逻辑简单,但在实际开发中一定要注意连接条件的准确性。如果连接条件写错了,比如把 emp.deptno = dept.deptno 错写成 emp.deptno = dept.loc,那结果就会完全错误,甚至可能导致性能问题。

内连接的优化

在大数据量场景下,内连接的性能优化也很重要。比如:

  1. 尽量在连接条件上使用索引:如果 emp.deptnodept.deptno 上有索引,数据库的查询效率会高很多。
  2. 避免不必要的字段参与连接:比如,如果只需要查询员工姓名和部门名称,就不要把整个员工表和部门表的所有字段都选出来。
  3. 合理使用子查询:有时候,先通过子查询过滤数据,再做内连接,效果会更好。

举个例子,假设我们想查薪资高于平均值的员工信息,可以这样写:

SELECT emp.ename, emp.sal
FROM emp INNER JOIN (SELECT AVG(sal) AS avg_sal FROM emp
) AS avg_table ON emp.sal > avg_table.avg_sal;

这样,先算出平均薪资,再和员工表做连接,效率会比直接写 WHERE emp.sal > (SELECT AVG(sal) FROM emp) 更高。


外连接

外连接的核心思想是“保留一张表的所有数据,即使另一张表没有匹配项”。这在统计报表、数据分析等场景下特别有用。

左外连接

左外连接(LEFT JOIN)的规则是:保留左表的所有记录,右表中没有匹配的部分用 NULL 补齐

比如,我们之前提到的学生表和成绩表的例子。学生表记录了所有学生的信息,成绩表记录了考试成绩。如果想查所有学生的成绩,即使有人没参加考试,也要显示他们的名字,这时候左外连接就是最佳选择。

具体 SQL 如下:

SELECT student.name, score.score
FROM student LEFT JOIN score ON student.id = score.id;

执行这条语句后,结果中会包含所有学生的名字,有成绩的显示具体分数,没成绩的则显示 NULL

左外连接的陷阱

虽然左外连接很实用,但新手常犯的一个错误是:在 ON 条件之外加 WHERE 条件时,不小心过滤掉了 NULL 值

比如,假设我们想查所有学生的成绩,并且只显示成绩大于 60 分的学生。如果这样写:

SELECT student.name, score.score
FROM student LEFT JOIN score ON student.id = score.id
WHERE score.score > 60;

结果就会变成:只有成绩大于 60 的学生会被显示,而那些没有成绩的学生(score 是 NULL)会被过滤掉。这时候,左外连接的效果就失效了。

正确的做法应该是:把筛选条件放在 ON 子句里,或者在 WHERE 中允许 NULL 值存在:

SELECT student.name, score.score
FROM student LEFT JOIN score ON student.id = score.id
AND score.score > 60;

这样,即使成绩小于 60,学生的名字也会被保留下来,只是对应的 score 字段是 NULL

右外连接

右外连接(RIGHT JOIN)和左外连接的逻辑是一样的,只不过方向相反。它会保留右表的所有记录,左表中没有匹配的部分用 NULL 补齐。

比如,如果我们想查所有的成绩记录,即使某个成绩对应的学号在学生表里找不到,也可以用右外连接:

SELECT student.name, score.score
FROM student RIGHT JOIN score ON student.id = score.id;

这时候,成绩表中的所有记录都会被保留,而学生表中找不到匹配项的部分会用 NULL 补齐。

不过,在实际开发中,右外连接的使用频率比左外连接低得多。因为大多数时候,我们更关注主表(比如学生表)的数据完整性,而成绩表通常是附属表。所以,左外连接已经能满足大部分需求了。

全外连接

MySQL 本身不支持全外连接(FULL OUTER JOIN),但可以通过左外连接和右外连接的联合查询来实现。

比如,如果我们想同时保留学生表和成绩表的所有记录,可以这样写:

SELECT student.name, score.score
FROM student LEFT JOIN score ON student.id = score.id
UNION
SELECT student.name, score.score
FROM student RIGHT JOIN score ON student.id = score.id;

这样,结果中会包含学生表和成绩表中所有记录的并集,没有匹配的地方用 NULL 补齐。


简单案例

为了让大家更直观地理解连接的用法,咱们再来看几个实际案例。

案例 1:列出所有部门及其员工信息

需求:显示每个部门的名称,以及该部门的所有员工姓名,包括没有员工的部门

这时候,显然要用外连接。因为内连接会过滤掉没有员工的部门,而外连接可以保留这些部门信息。

SQL 写法如下:

SELECT dept.dname, emp.ename
FROM dept LEFT JOIN emp ON dept.deptno = emp.deptno;

执行结果中,每个部门都会被列出来,有员工的显示员工姓名,没有员工的 ename 字段是 NULL

案例 2:查找没有订单的客户

假设我们有客户表 customers 和订单表 orders,现在想查哪些客户还没有下过订单。

这时候可以用左外连接:

SELECT customers.name
FROM customers LEFT JOIN orders ON customers.id = orders.customer_id
WHERE orders.order_id IS NULL;

这里的关键是 WHERE orders.order_id IS NULL,它表示在订单表中找不到匹配记录的客户。

案例 3:合并多个表的数据

有时候,我们需要同时连接多个表。比如,查询每个员工的姓名、部门名称以及薪资等级。

假设薪资等级存储在另一张表 salgrade 中,那么 SQL 可以这样写:

SELECT emp.ename, dept.dname, salgrade.grade
FROM emp
INNER JOIN dept ON emp.deptno = dept.deptno
INNER JOIN salgrade ON emp.sal BETWEEN salgrade.losal AND salgrade.hisal;

这样,就能把三张表的数据关联起来,获取更丰富的信息。


相关文章:

09.MySQL内外连接

09.MySQL内外连接 文章目录 MySQL内外连接 内连接 外连接 左外连接 右外连接 简单案例 MySQL内外连接 在数据库操作中,表的连接是一个非常重要的概念。简单来说,连接就是将两个或多个表中的数据按照某种规则结合起来,从而获取我们所需要的…...

Python爬虫实战:研究Scrapy-Splash库相关技术

1 引言 1.1 研究背景与意义 网络爬虫作为一种自动获取互联网信息的技术,在数据挖掘、信息检索、舆情分析等领域有着广泛的应用。然而,随着 Web 技术的不断发展,越来越多的网站采用 JavaScript 动态渲染技术,如 React、Vue 等框架构建的单页应用 (SPA)。这些网站的内容通常…...

智能升级:中国新能源汽车充电桩规模化建设与充电桩智慧管理方案

近年来,中国新能源汽车产业快速发展,市场规模持续扩大,但充电基础设施的建设与管理仍面临布局不均、利用率低、智能化水平不足等问题。为推动新能源汽车普及,国家正加速充电桩的规模化建设,并通过智慧化管理提升运营效…...

AlphaFold3服务器安装与使用(非docker)(1)

1. 服务器显卡驱动准备 这部分我会详细记录一下我踩过的坑及怎样拯救的,原谅啰嗦啦 ^_^ 1.1 服务器旧配置 1.1.1 nvidia-smi [xxxxxxlocalhost ~]# nvidia-smi Thu May 29 20:54:00 2025 -------------------------------------------------------------…...

接口自动化测试之pytest接口关联框架封装

🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 一般情况下,我们是通过一个yaml文件进行关联实现 在根目录下新建一个文件yaml,通过上述conftest.py文件实现全局变量的更新: 1.首先需要建…...

M1安装并使用Matlab2024a进行java相机标定

安装 Matlab下载地址:https://www.macxin.com/archives/23771.html注意⚠️:如若需要java调用Matlab函数,则需要java版本为21 使用 安装完成之后运行此节目可以看到: 构建jar 命令行输入deploytool,会有一个弹窗&a…...

02-Redis常见命令

02-Redis常见命令 Redis数据结构介绍 Redis是一个key-value的数据库,key一般是String类型,不过value的类型多种多样: 贴心小建议:命令不要死记,学会查询就好啦 Redis为了方便学习,将操作不同数据类型的命…...

【论文阅读笔记】Text-to-SQL Empowered by Large Language Models: A Benchmark Evaluation

文章目录 Text-to-SQL Empowered by Large Language Models: A Benchmark Evaluation一、论文基本信息1. 文章标题2. 所属刊物/会议3. 发表年份4. 作者列表5. 发表单位 二、摘要三、解决问题四、创新点五、自己的见解和感想六、研究背景七、研究方法(模型、实验数据…...

使用ArcPy进行栅格数据分析

设置工作环境 在开始编写脚本之前,需要设置好工作环境。这包括指定工作空间(workspace)和输出路径。工作空间是包含所有输入数据的文件夹或地理数据库,而输出路径则是处理结果将要保存的位置。 import arcpy from arcpy import …...

华为OD机试真题——告警抑制(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…...

Java转Go日记(五十七):gin 中间件

1. 全局中间件 所有请求都经过此中间件 package mainimport ("fmt""time""github.com/gin-gonic/gin" )// 定义中间 func MiddleWare() gin.HandlerFunc {return func(c *gin.Context) {t : time.Now()fmt.Println("中间件开始执行了&quo…...

《树数据结构解析:核心概念、类型特性、应用场景及选择策略》

在数据结构中,树是一种分层的非线性数据结构,由节点和边组成,具有唯一根节点、子树分层结构和无环特性。其核心价值在于高效处理层次化数据或动态集合,广泛应用于算法、数据库、文件系统等领域。 一、树的核心概念 根节点&#…...

在本地查看服务器上的TensorBoard

建立本地服务器与远程服务器的通信,将TensorBoard的映射端口与本地端口连接起来,本地终端运行: ssh -L 本地端口:127.0.0.1:TensorBoard端口 用户名服务器的IP地址 -p 服务器登录端口 e.g. ssh -L 10010:127.0.0.1:39353 sx110.92.137.56 -…...

硬件开发全解:从入门教程到实战案例与丰富项目资源

硬件开发全解:从入门教程到实战案例与丰富项目资源 一、硬件开发基础 1.1 硬件开发概述 硬件开发,简单来说,就是从构思到实现一个电子设备的全过程。这一过程涉及到电子电路设计、嵌入式系统编程、传感器和执行器的集成等多个关键领域。在电子…...

嵌入式学习笔记 - freeRTOS的两种临界禁止

一 禁止中断 通过函数taskENTER_CRITICAL() ,taskEXIT_CRITICAL()实现 更改就绪列表时,通常是通过禁止中断的方式,进入临界段,因为systick中断中有可以更改就绪列表的权利, 就绪列表(如 pxReadyTasksLis…...

202403-02-相似度计算 csp认证

其实这个问题就是求两篇文章的词汇的交集和并集,首先一说到并集,我就想到了set集合数据结构,set中的元素必须唯一。 STL之set的基本使用–博客参考 所以将两个文章的词汇全部加入set中,并求出set的大小,即为并集的大小…...

【Oracle】游标

个人主页:Guiat 归属专栏:Oracle 文章目录 1. 游标基础概述1.1 游标的概念与作用1.2 游标的生命周期1.3 游标的分类 2. 显式游标2.1 显式游标的基本语法2.1.1 声明游标2.1.2 带参数的游标 2.2 游标的基本操作2.2.1 完整的游标操作示例 2.3 游标属性2.3.1…...

MySQL 中 char 与 varchar 的区别

在 MySQL 的字段类型中,char和varchar是用来处理字符串。本文来学习二者区别 一、本质区别:空间分配的 “固执” 与 “灵活” 1. char:空间占满 固定长度特性: 定义时指定长度(如char(10)),无…...

DeepSeek 赋能智能零售,解锁动态定价新范式

目录 一、引言二、智能零售动态定价策略概述2.1 动态定价的概念与原理2.2 动态定价在智能零售中的重要性2.3 传统动态定价策略的局限性 三、DeepSeek 技术解析3.1 DeepSeek 的技术原理与架构3.2 DeepSeek 的优势与特点 四、DeepSeek 在智能零售动态定价中的应用机制4.1 数据收集…...

在Flutter中定义全局对象(如$http)而不需要import

在Flutter中定义全局对象(如$http)而不需要import 在Flutter中,有几种方法可以定义全局可访问的对象(如$http)而不需要在每个文件中import: 方法1:使用GetX的依赖注入(推荐&#x…...

<4>, Qt窗口

目录 一,菜单栏 二,工具栏 三,状态栏 四,浮动窗口 五,对话框 一,菜单栏 MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);// 创建菜单栏…...

6.04打卡

浙大疏锦行 DAY 43 复习日 作业: kaggle找到一个图像数据集,用cnn网络进行训练并且用grad-cam做可视化 进阶:并拆分成多个文件 损失: 0.502 | 准确率: 75.53% 训练完成 import torch import torch.nn as nn import torch.optim as optim from…...

【基于SpringBoot的图书购买系统】操作Jedis对图书图书的增-删-改:从设计到实战的全栈开发指南

引言 在当今互联网应用开发中,缓存技术已成为提升系统性能和用户体验的关键组件。Redis作为一款高性能的键值存储数据库,以其丰富的数据结构、快速的读写能力和灵活的扩展性,被广泛应用于各类系统的缓存层设计。本文将围绕一个基于Redis的图…...

Ubuntu中TFTP服务器安装使用

TFTP服务器 在 Ubuntu 下使用 TFTP(Trivial File Transfer Protocol) 服务,通常用于简单的文件传输(如网络设备固件更新、嵌入式开发等)。 1 TFTP服务器安装 sudo apt-get install tftp-hpa sudo apt-get install…...

Spring Boot微服务架构(十):Docker与K8S部署的区别

Spring Boot微服务在Docker与Kubernetes(K8S)中的部署存在显著差异,主要体现在技术定位、管理能力、扩展性及适用场景等方面。以下是两者的核心区别及实践对比: 一、技术定位与核心功能 Docker 功能:专注于单节点容器化…...

接口重试的7种常用方案!

前言 记得五年前的一个深夜,某个电商平台的订单退款接口突发异常,因为银行系统网络抖动,退款请求连续失败。 原本技术团队只是想“好心重试几次”,结果开发小哥写的重试代码竟疯狂调用了银行的退款接口 82次! 最终导致…...

vue3:Table组件动态的字段(列)权限、显示隐藏和左侧固定

效果展示 根据后端接口返回&#xff0c;当前登录用户详情中的页面中el-table组件的显示隐藏等功能。根据菜单id查询该菜单下能后显示的列。 后端返回的数据类型: 接收到后端返回的数据后处理数据结构. Table组件文件 <!-- 自己封装的Table组件文件 --> onMounted(()>…...

pikachu靶场通关笔记13 XSS关卡09-XSS之href输出

目录 一、href 1、常见取值类型 2、使用示例 3、安全风险 二、源码分析 1、进入靶场 2、代码审计 3、渗透思路 三、渗透实战 1、注入payload1 2、注入payload2 3、注入payload3 本系列为通过《pikachu靶场通关笔记》的XSS关卡(共10关&#xff09;渗透集合&#xff…...

MCP客户端Client开发流程

1. uv工具入门使用指南 1.1 uv入门介绍 MCP开发要求借助uv进行虚拟环境创建和依赖管理。 uv 是一个Python 依赖管理工具&#xff0c;类似于pip 和 conda &#xff0c;但它更快、更高效&#xff0c;并且可以更好地管理 Python 虚拟环境和依赖项。它的核心目标是 替代 pip 、…...

学习日记-day21-6.3

完成目标&#xff1a; 目录 知识点&#xff1a; 1.集合_哈希表存储过程说明 2.集合_哈希表源码查看 3.集合_哈希表无索引&哈希表有序无序详解 4.集合_TreeSet和TreeMap 5.集合_Hashtable和Vector&Vector源码分析 6.集合_Properties属性集 7.集合_集合嵌套 8.…...