【JavaWeb后端学习笔记】MySQL多表查询(内连接、外连接、子查询)
MySQL 多表查询
- 1、连接查询
- 1.1 内连接
- 1.2 外连接
- 2、子查询
- 2.1 标量子查询
- 2.2 列子查询
- 2.3 行子查询
- 2.4 表子查询
- 3、多表查询案例
多表查询有两大类:连接查询和子查询。
连接查询又分为隐式/显式内连接和左/右外连接。
子查询又分为标量子查询、列子查询、行子查询和表子查询。
多表查询是建立在单表查询的基础之上的,因此需要熟练单表查询。可以参考:【JavaWeb后端学习笔记】MySQL的数据查询语言(Data Query Language,DQL)
本文案例所需资料来自黑马程序员:多表查询
开始前需要运行01.数据准备.sql脚本中的代码,准备表和数据。
1、连接查询
1.1 内连接
内连接相当于查询A、B两个表交集部分数据。
内连接有两种:隐式内连接、显示内连接。他们的语法如下:
-- 隐式内连接语法
select 字段列表 from 表1,表2 where 连接条件...;-- 显示内连接语法
select 字段列表 from 表1 [inner] join 表2 on 连接条件...;
由于现在是多表查询的情况,因此在返回字段列表中,需要使用表名.字段名的格式。
连接条件是用来消除多余的笛卡尔积。一般会使用逻辑外键消除笛卡尔积。
下面分别使用隐式内连接和现实内连接的方式查询员工的姓名以及所属部门名称。
-- A. 查询员工的姓名 , 及所属的部门名称 (隐式内连接实现)
-- tb_emp表中的dept_id字段是关联到tb_dept表的逻辑外键,可以通过逻辑外键消除多余的笛卡尔积。
select tb_emp.name as name, tb_dept.name as department from tb_emp, tb_dept where tb_emp.dept_id = tb_dept.id;-- B. 查询员工的姓名 , 及所属的部门名称 (显式内连接实现)
-- 显式内连接只是在代码编写上将内连接展现出来,效果与隐式内连接相同
-- 显示内连接的连接条件写在 on 后面。
select tb_emp.name as name, tb_dept.name as department from tb_emp inner join tb_dept on tb_emp.dept_id = tb_dept.id;
这里可以注意一点,员工表中有17条数据,但是查出来的结果只有16条,缺少了员工姓名为“陈友谅”的数据,这是因为“陈友谅”的dept_id为null,他没有对应的部门,在部门表中没有id为null的数据,因此在内连接查询中,连接条件是不成立的,所以查询不到“陈友谅”的数据。但是为了保证员工数据的完整性,虽然“陈友谅”没有工作,也任然需要把他查询出来,这个时候就需要使用外连接查询。
1.2 外连接
外连接分为:左外连接和右外连接。
左外连接:查询左表所有数据(包括两张表的交集);
右外连接:查询右表所有数据(包括两张表的交集);
外连接语法如下:
-- 左外连接语法
select 字段列表 from 表1 left [outer] join 表2 on 连接条件...;-- 右外连接语法
select 字段列表 from 表1 right [outer] join 表2 on 连接条件...;
外连接的连接条件也是写在 “on” 后面。
下面分别使用左外连接和右外连接查询员工表所有员工的姓名, 和对应的部门名称:
-- A. 查询员工表 所有 员工的姓名, 和对应的部门名称 (左外连接)
-- 使用左外连接,为了查询出所有员工数据,将员工表tb_emp放在左边
select tb_emp.name as 员工姓名, tb_dept.name as 部门名称 from tb_emp left join tb_dept on tb_emp.dept_id = tb_dept.id;-- B. 查询部门表 所有 部门的名称, 和对应的员工名称 (右外连接)
-- 使用右外连接,为了查询出所有员工数据,将员工表tb_emp放在右边
select tb_emp.name as 员工姓名, tb_dept.name as 部门名称 from tb_dept right join tb_emp on tb_emp.dept_id = tb_dept.id;
从查询结果可以发现,虽然“陈友谅”的dept_id为null,但是该员工任然查询出来了。这是因为外连接保证了查询出某一边表格的所有数据。
2、子查询
SQL语句中嵌套select语句,称为嵌套查询,又称子查询。
子查询语法:
-- 子查询语法(形式不固定)
select * from t1 where column1 = (select column2 from t2 ...);select * from (select * from t1 where 条件查询条件) t left join t2 on 连接条件;......
子查询外部的语句可以是insert/update/delete/select的任何一个,最常见的是select
| 子查询 | 返回结果及常用操作符 |
|---|---|
| 标量子查询 | 返回的结果为单个值;常用操作符:= 、<>、>、>=、<、<= |
| 列子查询 | 返回的结果为一列;常用操作符:in、not in等 |
| 行子查询 | 返回的结果为一行;常用操作符:=、<>、in、not in |
| 表子查询 | 返回的结果为多行多列;常用操作符:in |
2.1 标量子查询
标量子查询返回的结果为单个值。
可以与返回结果比较大小,因此常用操作符有:= 、<>、>、>=、<、<=。
案例1:查询 “教研部” 的所有员工信息。
分析:首先需要查询出教研部的id,然后使用员工表中的dept_id与教研部id判断是否相等。
-- 查询 "教研部" 的所有员工信息
-- (select id from tb_dept where name = '教研部') 标量子查询查询出教研部id
select * from tb_emp where dept_id = (select id from tb_dept where name = '教研部');
案例2:查询在 “方东白” 入职之后的员工信息。
分析:首先查询出姓名为 "方东白"的员工的入职时间,然后与该入职时间比较。
-- 查询在 "方东白" 入职之后的员工信息
-- (select entrydate from tb_emp where name = '方东白') 标量子查询查询出"方东白" 入职时间
select * from tb_emp where entrydate > (select entrydate from tb_emp where name = '方东白');
2.2 列子查询
列子查询返回的结果为一列。
列子查询返回结果相当于一个列表或者集合,可以判断某个字段值是否在这个列表之中,因此常用操作符有:in、not in等。
案例:查询 “教研部” 和 “咨询部” 的所有员工信息。
分析:需要查询出"教研部" 和 "咨询部"的id,组成一个集合。通过判断员工所属的dept_id是否在这个集合内来查询结果。
-- 查询 "教研部" 和 "咨询部" 的所有员工信息。
-- (select id from tb_dept where tb_dept.name in ('教研部', '咨询部') 列子查询返回'教研部' 和 '咨询部'的id集合
select * from tb_emp where dept_id in (select id from tb_dept where tb_dept.name in ('教研部', '咨询部'));
2.3 行子查询
行子查询返回的结果为一行。
行子查询返回结果为表中一行完整数据或部分数据,可以与这一行数据的任意字段进行比较,常用操作符有:=、<>、in、not in。
案例:查询与 “韦一笑” 的入职日期 及 职位都相同的员工信息 。
分析:首先需要查询出 “韦一笑” 的入职日期 及 职位。然后根据这些信息进行判断。由于要对两个字段同时进行判断,因此可以用 ( ) 将这两个字段括起来同时判断。
-- 查询与 "韦一笑" 的入职日期 及 职位都相同的员工信息 ;-- 首先尝试采用标量子查询,分别查询出"韦一笑"的入职日期 及 职位,但是这样就需要两次子查询,性能较低。
select * from tb_emp where entrydate = (select entrydate from tb_emp where name = '韦一笑') and job = (select job from tb_emp where name = '韦一笑') and name != '韦一笑';-- 采用行子查询,查询出的结果为一行,可以将需要比较的字段用 ( ) 括起来进行比较
select * from tb_emp where (entrydate, job) = (select entrydate, job from tb_emp where name = '韦一笑') and name != '韦一笑';
2.4 表子查询
表子查询返回的结果为多行多列。
常用操作符为:in。
案例:查询入职日期是 “2006-01-01” 之后的员工信息 , 及其部门名称
分析:有两种思路。第一种,先建立员工表与部门表的外连接,通过逻辑外键消除多余的笛卡尔积,然后判断入职时间。第二种,先通过select返回入职时间在 “2006-01-01” 之后的员工子表,然后建立外连接,通过逻辑外键消除多余的笛卡尔积。推荐使用外连接,保证员工信息完整。
--查询入职日期是 "2006-01-01" 之后的员工信息 , 及其部门名称-- 先建立外连接,后判断入职时间
select tb_emp.*, tb_dept.name as 部门名称 from tb_emp left join tb_dept on tb_emp.dept_id = tb_dept.id where tb_emp.entrydate > '2006-01-01';-- 表子查询。先查询出入职时间在 "2006-01-01" 之后员工信息子表,然后建立外连接。
select e.*, d.name 部门名称 from (select * from tb_emp where entrydate > '2006-01-01') e left join tb_dept d on e.dept_id = d.id;
3、多表查询案例
准备数据:执行01.多表查询数据准备.sql脚本。
从案例-多表查询.vsdx中可以看到四张表的详细信息。
-- 1. 查询价格低于 10元 的菜品的名称 、价格 及其 菜品的分类名称 .
-- 子查询
select d.name 名称, d.price 价格, c.name 分类
from (select * from dish where price < 10) d left join category c on d.category_id = c.id;
-- 内连接
select d.name 菜品名称, d.price 价格, c.name 菜品分类
from dish d, category c
where d.category_id = c.id and d.price < 10;-- 2. 查询所有价格在 10元(含)到50元(含)之间 且 状态为'起售'的菜品名称、价格 及其 菜品的分类名称 (即使菜品没有分类 , 也需要将菜品查询出来).
-- 子查询
select d.name 名称, d.price 价格, c.name 分类
from (select * from dish where price between 10 and 50 and status = 1) d left join category c on d.category_id = c.id;
-- 左外连接
select d.name 菜品名称, d.price 价格, c.name 菜品分类
from dish d left join category c on d.category_id = c.id
where d.price between 10 and 50 and d.status = 1;-- 3. 查询每个分类下最贵的菜品, 展示出分类的名称、最贵的菜品的价格 .
select c.name 分类名称, max(d.price) 最大价格
from dish d, category c
where d.category_id = c.id
group by c.name;-- 4. 查询各个分类下 状态为 '起售' , 并且 该分类下菜品总数量大于等于3 的 分类名称 .
select c.name 分类名称
from dish d, category c
where d.category_id = c.id and d.status = 1
group by c.name
having count(*) >= 3;-- 5. 查询出 "商务套餐A" 中包含了哪些菜品 (展示出套餐名称、价格, 包含的菜品名称、价格、份数).
select s.name 套餐名称,s.price 套餐价格,d.name 菜品名称,d.price 菜品价格,sd.copies 菜品份数
from dish d,setmeal_dish sd,setmeal s
where d.id = sd.dish_idand sd.setmeal_id = s.idand s.name = '商务套餐A';-- 6. 查询出低于菜品平均价格的菜品信息 (展示出菜品名称、菜品价格).
select name, price
from dish
where price < (select avg(price) from dish);
相关文章:
【JavaWeb后端学习笔记】MySQL多表查询(内连接、外连接、子查询)
MySQL 多表查询 1、连接查询1.1 内连接1.2 外连接 2、子查询2.1 标量子查询2.2 列子查询2.3 行子查询2.4 表子查询 3、多表查询案例 多表查询有两大类:连接查询和子查询。 连接查询又分为隐式/显式内连接和左/右外连接。 子查询又分为标量子查询、列子查询、行子查询…...
RocketMQ 过滤消息 基于tag过滤和SQL过滤
RocketMQ 过滤消息分为两种,一种tag过滤,另外一种是复杂的sql过滤。 tag过滤 首先创建producer然后启动,在这里创建了字符串的数组tags。字符串数组里面放置了多个字符串,然后去发送15条消息。 15条消息随着i的增长,…...
element-ui 基本样式的一些更改【持续更新】
1、 去除el-tabs的底部灰色横线 ::v-deep .el-tabs__nav-wrap::after {height: 0px;}2、el-table设置表头颜色 <el-table:data"tableData":header-cell-style"{background:#F7F8FA,color:#4E5869}"><el-table-columnlabel"序号"type&qu…...
element-ui radio和checkbox禁用时不置灰还是原来不禁用时的样式
把要紧用的内容加上一个class"notEdit-page" z注意要在style里面写不能加上scoped /*//checkBox自定义禁用样式*//*//checkBox自定义禁用样式*/ .notEdit-page.el-checkbox__input.is-disabled.is-checked.el-checkbox__inner::after {border-color: #fff; } .notEdi…...
第一部分:基础知识 6. 函数 --[MySQL轻松入门教程]
MySQL 提供了丰富的内置函数,涵盖了字符串处理、数值计算、日期时间操作、聚合分析以及控制流等多个方面。这些函数可以帮助用户更高效地进行数据查询和处理。 1.字符串函数 MySQL 提供了丰富的字符串函数来帮助用户处理和操作字符串数据。下面是一些常用的 MySQL…...
【蓝桥杯每日一题】扫雷
扫雷 知识点 2024-12-3 蓝桥杯每日一题 扫雷 dfs (bfs也是可行的) 题目大意 在一个二维平面上放置这N个炸雷,每个炸雷的信息有$(x_i,y_i,r_i) $,前两个是坐标信息,第三个是爆炸半径。然后会输入M个排雷火箭࿰…...
【算法】棋盘覆盖问题源代码及精简版
目录 一、题目 二、样例 三、示例代码 四、精简代码 五、总结 对于棋盘覆盖问题的解答和优化。 一、题目 输入格式: 第一行,一个整数n(棋盘n*n,n确保是2的幂次,n<64) 第二行,两个整数…...
Django的介绍
Django是一个高级的Python Web框架,它鼓励快速开发和干净、实用的设计。Django遵循MVC设计模式,即模型(Model)、视图(View)和控制器(Controller),并提供了一个即时可用的…...
【Spring工具插件】lombok使用和EditStarter插件
阿华代码,不是逆风,就是我疯 你们的点赞收藏是我前进最大的动力!! 希望本文内容能够帮助到你!! 目录 引入 一:lombok介绍 1:引入依赖 2:使用 3:原理 4&…...
掌控时间,成就更好的自己
在个人成长的道路上,时间管理是至关重要的一环。有效的时间管理能够让我们更加高效地完成任务,实现自己的目标,不断提升自我。 时间对每个人都是公平的,一天只有 24 小时。然而,为什么有些人能够在有限的时间里做出卓…...
Ruby On Rails 笔记2——表的基本知识
Active Record Basics — Ruby on Rails Guides Active Record Migrations — Ruby on Rails Guides 原文链接自取 1.Active Record是什么? Active Record是MVC模式中M的一部分,是负责展示数据和业务逻辑的一层,可以帮助你创建和使用Ruby…...
【AI系统】EfficientNet 系列
EfficientNet 系列 本文主要介绍 EffiicientNet 系列,在之前的文章中,一般都是单独增加图像分辨率或增加网络深度或单独增加网络的宽度,来提高网络的准确率。而在 EfficientNet 系列论文中,会介绍使用网络搜索技术(NAS)去同时探索…...
【Python小白|Python内置函数学习2】Python有哪些内置函数?不需要导入任何模块就可以直接使用的!现在用Python写代码的人还多吗?
【Python小白|Python内置函数学习2】Python有哪些内置函数?不需要导入任何模块就可以直接使用的!现在用Python写代码的人还多吗? 【Python小白|Python内置函数学习2】Python有哪些内置函数?不需要导入任何模块就可以直接使用的&a…...
蓝桥杯分治
P1226 【模板】快速幂 题目描述 给你三个整数 𝑎,𝑏,𝑝a,b,p,求 𝑎𝑏 mod 𝑝abmodp。 输入格式 输入只有一行三个整数,分别代表 𝑎,𝑏,𝑝a,b,p。…...
YOLOv8实战无人机视角目标检测
本文采用YOLOv8作为核心算法框架,结合PyQt5构建用户界面,使用Python3进行开发。YOLOv8以其高效的实时检测能力,在多个目标检测任务中展现出卓越性能。本研究针对无人机目标数据集进行训练和优化,该数据集包含丰富的无人机目标图像…...
三、【docker】docker和docker-compose的常用命令
文章目录 一、docker常用命令1、镜像管理2、容器管理3、容器监控和调试4、网络管理5、数据卷管理6、系统维护7、实用组合命令8、常用技巧二、docker-compose常用命令1、基本命令2、构建相关3、运行维护4、常用组合命令5、实用参数 一、docker常用命令 1、镜像管理 # 查看本地…...
Qt 2D绘图之五:图形视图框架的结构、坐标系统和框架间的事件处理与传播
参考文章链接: Qt 2D绘图之五:图形视图框架的结构和坐标系统 Qt 2D绘图之六:图形视图框架的事件处理与传播 图形视图框架的结构 在前面讲的基本绘图中,我们可以自己绘制各种图形,并且控制它们。但是,如果需要同时绘制很多个相同或不同的图形,并且要控制它们的移动、…...
基于SpringBoot+Vue的美妆购物网站
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...
MySQL之创建和管理表
目录 1. MySQL中的数据类型编辑编辑 2. 创建和管理数据库 方式1:创建数据库 方式2:创建数据库并指定字符集 方式3:判断数据库是否已经存在,不存在则创建数据库( 推荐 ) 总结 2.2 使用数据库 查看当…...
肌肉骨骼肿瘤治疗市场:潜力无限,未来可期
肌肉骨骼肿瘤治疗作为现代医学的重要分支,专注于应对骨骼和肌肉系统中的良性和恶性肿瘤。随着全球人口老龄化和生活方式的改变,肌肉骨骼疾病日益成为公共卫生的重要问题。与此同时,医疗技术的进步和患者对高质量医疗服务的需求不断推动该市场…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...
