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

05MySQL多表查询全解析

mysql的多表查询

概述:

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

多表查询-笛卡尔积

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

-- 笛卡尔查询,不过滤无用信息
SELECT * FROM emp,dept;-- 内连接查询,可以过滤无用信息
SELECT * FROM emp,dept where emp.dept_id = dept.id order by emp.id asc;

多表查询-内连接查询

内连接查询的是两张表交集的部分

语法:

隐式内连接:

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

显示内连接:

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

-- 隐式内连接
SELECT e.name,d.name
FROM emp e,dept d
WHERE e.dept_id=d.id;-- 显示内连接
SELECT e.name,d.name
FROM emp e
INNER JOIN dept d
ON e.dept_id=d.id;

在实际开发中,推荐使用显式内连接的写法,尤其是在多表连接时,INNER JOIN的语法能更清晰地体现表之间的关系,使代码更易读、易维护。

多表查询-外连接查询

语法:

左外连接查询

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

返回表1的所有记录,以及表2与表1满足连接条件的记录

右外连接查询

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

返回表2的所有记录,以及表1与表2满足连接条件的记录

左右外连接常用于需要完整保留主表数据并关联从表信息的场景

-- 外连接演示
-- 查询emp表的所有数据,和对应的部门信息(左外连接)
SELECT e.*,d.name AS d_name
FROM emp e
LEFT OUTER JOIN dept d
ON e.dept_id=d.id;-- 查询dept表的所有数据,和对应的员工信息(右外连接)
SELECT d.*,e.*
FROM emp e
RIGHT OUTER JOIN dept d
ON e.dept_id=d.id;

多表查询-自连接查询

自连接查询是 SQL 中一种特殊的多表查询方式,它指的是同一张表与自身进行连接,通常用于处理表中存在层级关系或自引用关系的数据。

例如,在员工表中,可能有一个 manager_id 字段指向该员工的上级领导(也是员工表中的一条记录),这时就可以通过自连接查询员工与其上级的信息。

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

自连接的内连接查询:

SELECT 字段列表 FROM  表A 别名a,表A 别名b  WHERE  条件语句;

自连接的外连接查询:

SELECT 字段列表 FROM 表A 别名a [左/右] JOIN 表A 别名b  ON 条件语句;

-- 1. 查询员工	及其	所属领导的名字
SELECT a.name '员工',b.name '上司' FROM emp a,emp b WHERE a.managerid=b.id; -- 2. 查询所有员工 emp 及其领导的名字 emp,如果员工没有领导,也需要查询出来
SELECT a.name '员工',b.name '上司' FROM emp a left join emp b ON a.managerid=b.id;

多表查询-联合查询

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

联合查询语法:

SELECT 字段列表 FROM 表A ...
UNION [ALL]
SELECT 字段列表 FROM 表B ...;

如果添加all参数,则会显示重复的记录,不添加就是去重

-- 1.将薪资低于5000的员工,和年龄大于50岁的员工全部查询出来。
SELECT * FROM emp WHERE age >50
union 
SELECT * FROM emp WHERE salary < 5000;

多表查询-子查询

子查询:

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

SELECT  *  FROM  t1  WHERE  column1=(SELECT  column1  FROM  t2);
子查询外部的语句可以是INSERT/UPDATE/DELETE/SELECT的任何一个。

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

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

根据子查询位置,分为:WHERE之后、FROM之后、SELECT之后。

标量子查询

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

-- 标量子查询-- 1.查询“销售部”的所有员工信息
-- a.查询“销售部”部门ID
-- b.根据销售部部门ID,查询员工信息
SELECT * 
FROM emp 
WHERE dept_id=(SELECT id FROM dept WHERE name='销售部');-- 2.查询在“方东白”入职之后的员工信息
-- a.查询方东白的入职日期
-- b.查询指定入职日期之后入职的员工信息
SELECT * 
FROM emp 
WHERE entrydate >= (SELECT entrydate FROM emp WHERE name='方东白');

列子查询

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

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

IN   判断字段是否在这些值中,如果符合则返回        
NOT  IN与IN相反
ANY满足任意一个则返回
SOME完全等于any
ALL必须所有值都满足才返回
-- 列子查询
-- 1.查询“销售部”和“市场部”的所有员工信息
-- a.查询“销售部”和“市场部”的部门ID
SELECT id FROM dept WHERE name = '销售部' OR name = '市场部';
-- b.根据部门ID,查询员工信息
SELECT * FROM emp WHERE dept_id IN (SELECT id FROM dept WHERE name = '销售部' OR name = '市场部');
SELECT * FROM emp WHERE dept_id NOt IN (2,4,6);
-- 2.查询比财务部所有人工资都高的员工信息
-- a.查询所有财务部人员工资
SELECT salary FROM emp WHERE dept_id = (SELECT id FROM dept WHERE name = '财务部');
-- b.比财务部所有人工资都高的员工信息
SELECT * FROM emp WHERE salary > ALL (SELECT salary FROM emp WHERE dept_id = (SELECT id FROM dept WHERE name = '财务部'));-- 3.查询比研发部其中任意一人工资高的员工信息
-- a.查询研发部所有人工资
SELECT salary FROM emp WHERE dept_id = (SELECT id FROM dept WHERE name = '研发部');
-- b.比研发部其中任意一人工资高的员工信息
SELECT * FROM emp WHERE salary > ANY (SELECT salary FROM emp WHERE dept_id = (SELECT id FROM dept WHERE name = '研发部'));
SELECT * FROM emp WHERE salary > SO(SELECT salary FROM emp WHERE dept_id = (SELECT id FROM dept WHERE name = '研发部'));

行子查询

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

常用的操作符:=、<>、IN、NOT IN

-- 行子查询
-- 1.查询与“张无忌”的薪资及直属领导相同的员工信息;
-- a.查询“张无忌”的薪资及直属领导
SELECT salary,managerid FROM emp WHERE name ='张无忌';
--  b.查询与“张无忌”的薪资及直属领导相同的员工信息;
SELECT * FROM emp WHERE (salary,managerid) = (12500,1);
SELECT * FROM emp WHERE (salary,managerid) = (SELECT salary,managerid FROM emp WHERE name ='张无忌');

表子查询

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

可以这样简单理解,但更准确地说,表子查询(Table Subquery)是指子查询返回的结果是一个多行多列的数据集(类似一张 “临时表”),主查询会基于这个 “临时表” 来进行进一步的查询操作(比如关联查询、IN 匹配等)。

-- 表子查询-- 1.查询与“鹿杖客”,“宋远桥”的职位和薪资相同的员工信息
-- a.查询“鹿杖客”,“宋远桥”的职位和薪资
SELECT salary,job FROM emp WHERE name= '鹿杖客' OR name= '宋远桥';
-- b.查询与“鹿杖客”,“宋远桥”的职位和薪资相同的员工信息
SELECT * FROM emp WHERE (salary,job) IN (SELECT salary,job FROM emp WHERE name= '鹿杖客' OR name= '宋远桥');-- 2.查询入职日期是"2006-01-01"之后的员工信息,及其部门信息
-- a.入职日期是"2006-01-01"之后的员工信息
SELECT * FROM emp WHERE entrydate > '2006-01-01';
-- b.查询这部分员工,对应的部门信息;
SELECT e.*,d.* FROM (SELECT * FROM emp WHERE entrydate > '2006-01-01') e left join dept d ON e.dept_id=d.id;

多表查询--综合练习

-- 1.查询员工的姓名、年龄、职位、部门信息(隐式内连接)
SELECT e.name,e.age,e.job,d.name
FROM emp e,dept d
WHERE e.dept_id=d.id;-- 2.查询年龄小于30岁的员工的姓名、年龄、职位、部门信息(显式内连接)
SELECT e.name,e.age,e.job,d.name
FROM emp e
INNER JOIN dept d
ON e.dept_id=d.id
WHERE e.age < 30;-- 3.查询拥有员工的部门ID、部门名称
SELECT DISTINCT  d.id,d.name
FROM emp e,dept d
WHERE e.dept_id=d.id;-- 4.查询所有年龄大于40岁的员工,及其归属的部门名称;如果员工没有分配部门,也需要展示出来
SELECT e.*,d.name
FROM emp e
LEFT OUTER JOIN dept d
ON e.dept_id=d.id
WHERE e.age > 40;-- 5.查询所有员工的工资等级
SELECT e.*,s.grade
FROM emp e,salgrade s
WHERE e.salary BETWEEN s.losal AND s.hisal;-- 6.查询“研发部”所有员工的信息及工资等级
SELECT e.*,d.name,s.grade
FROM emp e,dept d, salgrade s
WHERE e.dept_id=d.id
AND d.name = '研发部'
AND e.salary BETWEEN s.losal AND s.hisal;-- 7.查询“研发部”员工的平均工资
SELECT avg(e.salary)
FROM emp e,dept d
WHERE d.name= '研发部' AND e.dept_id=d.id-- 8.查询工资比“灭绝”高的员工信息。
SELECT e.*
FROM emp e
WHERE salary > (SELECT salary FROM emp e WHERE name='灭绝')-- 9.查询比平均薪资高的员工信息
SELECT * 
FROM emp 
WHERE salary > (SELECT avg(salary) FROM emp  );-- 10.查询低于本部门平均工资的员工信息
SELECT e2.* FROM emp e2 
WHERE salary < (SELECT avg(salary) FROM emp e1 WHERE e1.dept_id=e2.dept_id);-- 11.查询所有的部门信息,并统计部门的员工人数
SELECT d.id,d.name,(SELECT count(*) FROM emp e WHERE e.dept_id=d.id) FROM dept d;

这是我的个人学习笔记,主要用于记录自己对知识点的理解和梳理。由于目前仍在学习探索阶段,内容中难免存在理解偏差或表述疏漏,恳请各位大佬不吝赐教,多提宝贵意见~ 若有不同看法,欢迎理性交流探讨,感谢包容与指正!

http://www.xdnf.cn/news/19250.html

相关文章:

  • 使用axios封装post和get
  • RLPD——利用离线数据实现高效的在线RL:不进行离线RL预训练,直接应用离策略方法SAC,在线学习时对称采样离线数据
  • unity学习——视觉小说开发(二)
  • 【系统分析师】高分论文:论软件的系统测试及应用
  • 宽带有丢包,重传高的情况怎么优化
  • 2025板材十大品牌客观评估报告—客观分析(三方验证权威数据)
  • 【电力电子】MCP602运算放大器测交流电压(120VAC/230VAC),带直流偏置2.5V,比例:133.5:1
  • 【开题答辩全过程】以 “与我同行”中华传统历史数字化平台的设计和分析-------为例,包含答辩的问题和答案
  • 桌面GIS软件设置竖排文字标注
  • PAT 1088 Rational Arithmetic
  • Python文字识别OCR
  • 蓓韵安禧活性叶酸优生优育守护者
  • CSS基础学习第二天
  • 简说DDPM
  • 【系列07】端侧AI:构建与部署高效的本地化AI模型 第6章:知识蒸馏(Knowledge Distillation
  • 监听nacos配置中心数据的变化
  • vector的学习和模拟
  • 桌面GIS软件添加设置牵引文字标注
  • Fortran二维数组去重(unique)算法实战
  • 电子健康记录风险评分与多基因风险评分的互补性与跨系统推广性研究
  • 福彩双色球第2025100期篮球号码分析
  • GESP5级2024年03月真题解析
  • Coze源码分析-API授权-获取令牌列表-后端源码
  • UNet改进(36):融合FSATFusion的医学图像分割
  • TensorFlow 面试题及详细答案 120道(71-80)-- 性能优化与调试
  • Next.js 快速上手指南
  • 数值分析——算法的稳定性
  • 【ACP】2025-最新-疑难题解析- 练习二汇总
  • 文档转换总出错?PDF工具免费功能实测
  • Docker 部署深度网络模型(Flask框架思路)