【MYSQL】 复合查询--详解(重点)

先给大家抛一个结论,MYSQL中一切皆表格

前面我们讲解的mysql表的查询都是对一张表进行查询,在实际开发中这远远不够。

注意:这篇文章的相关指令我进行了补充,所以目录里的内容不代表全部,有的我没有用目录表示,但文章内容很齐全,内容很详细,方便大家学习

一. 基本查询回顾

1.查询工资高于500或岗位为MANAGER的雇员


2.查询工资高于500或岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为大写的J


3.按照部门号升序而雇员的工资降序排序


4.按部门编号升序、同一部门内按工资降序,查询员工的姓名、工资和部门编号。


5.使用年薪进行降序排序

计算每位员工的"年薪"(月薪 × 12 + 年度奖金),其中奖金为 NULL 的按 0 计算。

使用年薪进行降序排序


6.显示工资最高的员工的名字和工作岗位

  • 表中薪资最高的
  • 薪资为5000的人员信息
  • 显示工资最高的员工的名字和工作岗位

这个显示的是全部信息

显示的名字和工作岗位


7.显示工资高于平均工资的员工信息

查询平均工资

显示工资高于平均工资的员工信息


8.显示每个部门的平均工资和最高工资

显示每个部门的平均工资和最高工资

带部门编号

这里进行了格式化处理fromat(),保留了两位小数

在 MySQL 中的两种别名写法

MySQL 支持两种别名写法,效果完全一样

写法1:不用 AS

复制代码
SELECT max(sal) 最高 FROM EMP;

写法2:用 AS(更规范/标准)

复制代码
SELECT max(sal) AS 最高 FROM EMP;

两种都正确,MySQL 都认。

9.显示平均工资高于2000的部门号和它的平均工资

显示平均工资高于2000的部门号和它的平均工资

显示平均工资不高于2000的部门号和它的平均工资

10.显示每种岗位的雇员总数,平均工资

显示岗位雇员总数量

显示每个部门工作岗位的人数,并对这些岗位的人数进行升序排序

二.多表查询

**实际开发中往往数据来自不同的表,所以需要多表查询。本节我们用一个简单的公司管理系统,有三张表EMP,DEPT,SALGRADE来演示如何进行多表查询。**将数据进行穷举组合 ------ 笛卡尔积)

进行练习:

笛卡尔积(Cartesian Product)

1. 什么是笛卡尔积?

将两张表所有行进行无条件组合,左表的每一行与右表的每一行都匹配一次。

2. 产过程(你原来的描述,优化后保留)

  1. 从第一张表中取出第一条记录,与第二张表的所有记录依次组合;

  2. 再从第一张表中取出第二条记录,同样与第二张表的所有记录组合;

  3. 依次类推,直到第一张表的所有记录都组合完毕。

如果不加任何过滤条件,得到的结果就是笛卡尔积

3. 笛卡尔积的行数公式

结果行数 = 表1行数 × 表2行数

示例:

  • EMP 表:14 行

  • DEPT 表:4 行

  • 笛卡尔积 = 14 × 4 = 56 行

4. 使用笛卡尔积的典型问题

  • 大部分组合是没有实际意义的(例如:SMITH 与 部门 40 匹配,但他并不在部门40)

  • 会产生大量冗余数据,严重影响性能

5. 如何解决:加过滤条件(连接条件)

复制代码
-- 错误:笛卡尔积(无意义)
SELECT * FROM EMP, DEPT;

-- 正确:只保留部门编号相同的有效组合
SELECT * FROM EMP, DEPT
WHERE EMP.DEPTNO = DEPT.DEPTNO;

这也是 等值连接 的起源。

补充:

笛卡尔积是连接查询的"原始素材",必须通过连接条件(如 WHERE)过滤出有意义的行,才能得到正确的查询结果。

**显示雇员名、雇员工资以及所在部门的名字因为上面的数据来自EMP和DEPT表,因此要联合查(**将数据进行穷举组合 ------ 笛卡尔积)

其实我们只要emp表中的deptno = dept表中的deptno字段的记录


显示部门号为10的部门名,员工名和工资

显示的全部信息

显示部门号为10的部门名,员工名和工资

显示部门号为10的部门名,员工名,工资和部门号


显示各个员工的姓名,工资,及工资级别

查询 EMP 表和 SALGRADE 表的所有列,进行无条件组合,得到两张表的笛卡尔积

查询所有员工的姓名、工资以及可能对应的工资等级

显示各个员工的姓名,工资,及工资级别(后面有where的筛选条件)

补充hisal和losal的字段

LOSAL = 该等级的最低工资(Low Salary)

HISAL = 该等级的最高工资(High Salary)

两者共同定义了一个工资区间,用来判断员工属于哪个工资等级。

EMP.deptno 这个写法的三个作用

作用 说明
消除歧义 告诉数据库"我指的是 EMP 表的 deptno"
提高可读性 别人看 SQL 就知道这个字段来自哪张表
避免错误 防止因字段名重复导致的 ambiguous 错误

三.自连接

自连接是指在同一张表连接查询
这是同一张表(SALGRADE),只是起了两个不同的别名(t1 和 t2),然后对自己做笛卡尔积。 并不是两张不同的表,而是一张表自己跟自己连接 ,这种操作叫做自连接(Self Join)

显示员工FORD的上级领导的编号和姓名(mgr是员工领导的编号--empno)

使用的子查询:

使用多表查询(自查询)

  • 使用到表的别名
  • from emp e1, emp e2,给自己的表起别名,因为要先做笛卡尔积,所以别名可以先识别
  1. FROM EMP e1, EMP e2 对同一张 EMP 表起两个不同的别名:e1(左表)、e2(右表)

  2. 数据库先根据别名,将一张表逻辑上视为两张独立的表

  3. 然后对 e1e2 做笛卡尔积(e1 的每一行 × e2 的每一行)

  4. 最后通过 WHERE 条件过滤出符合条件的行

步骤 说明
把 EMP 表当作两个独立角色:e1(下属表)、e2(上级表)
先做笛卡尔积:每个"下属"与所有"上级"组合
过滤出 e1.ename = 'FORD'(下属是 FORD)
再过滤 e1.mgr = e2.empno(FORD 的上级编号 = 上级表的员工编号)
最终输出:FORD 的上级的姓名和编号

别名的作用

没有别名时,数据库无法区分"谁是上级""谁是下属";有了别名,才能写 e1.mgr = e2.empno

别名的原因:(重点补充)

自连接的核心问题

同一张表在 SQL 语句中出现两次,如果不加别名,数据库不知道 mgrempno 的对比是在同一行内还是跨行。

4.子查询

  • 子查询:SQL 中嵌套的 SELECT 语句,也叫嵌套查询。

  • 常见位置:WHERE / SELECT / FROM / HAVING / EXISTS

  • 核心理解:子查询的结果,在逻辑上始终是一张临时表(即使是单值,也是一行一列的表)。

  • 执行顺序:子查询先执行,结果再交给外层查询使用。

  • 当前学习重点 :子查询在 WHERE 子句中作为判断条件(如 IN=> 等)。

(1)单行子查询

返回一行记录的子查询

单行子查询 :子查询返回一行记录 (可以是一列或多列),外层查询使用单行比较运算符(如 =><>=<=<>)与子查询结果进行比较。
显示SMITH同一部门的员工

分步理解查询


一步到位查询:


(2)多行子查询

返回多行记录的子查询

多行子查询返回多行记录,必须配合 INANYALL等运算符使用,不能直接用 =

in关键字

in 关键字用来判断一个对应的列值是否在某个集合当中,只要在集合当中,表明说查找成功。

查询与 10 号部门员工 (CLERK、MANAGER、PRESIDENT)拥有相同职位,但自己不在 10 号部门的员工信息。

sql 复制代码
SELECT ename, job, sal, deptno 
FROM EMP 
WHERE job IN (
    SELECT DISTINCT job 
    FROM EMP 
    WHERE deptno = 10
) 
AND deptno <> 10;

先通过子查询找出"职位与 10 号部门相同但自己不在 10 号部门"的员工,再关联部门表查出他们所在的部门名称。

执行顺序:最内层(10号部门的职位)→ 中间层(符合条件且不在10号的员工)→ 外层(关联部门表得到部门名称)。

SQL 是三层嵌套结构 ,执行顺序严格遵循 由最内层向外层依次执行 的原则
这样执行的原因是:

外层查询依赖于内层查询的结果。

  • 第 1 步(最内层)SELECT ... FROM EMP WHERE deptno = 10

    • 不依赖外面的任何查询。它自己就能独立运行,得到一个结果集(10号部门的职位列表)。
  • 第 2 步(中间层)SELECT ... FROM EMP WHERE job IN ( ... )

    • 这里的 ( ... ) 代表第 1 步的结果

    • 如果第 1 步没执行完,数据库就不知道 IN 里面应该有哪些职位,第 2 步就无法执行。

  • 第 3 步(最外层)SELECT ... FROM tmp, DEPT ...

    • 这里的 tmp 代表第 2 步的结果

    • 如果第 2 步没执行完,数据库就不知道 tmp 这张临时表里有什么数据,第 3 步就无法执行。

all关键字

all 关键字表示与所有的值作比较。

sql 复制代码
select ename, sal, deptno from EMP where sal > all(select sal from EMP where
deptno=30);

部门30的最高工资:

显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号

另一种写法:

any关键字

any 关键字表示与任意的值作比较。
显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门
的员工)

查询出工资大于 30 号部门中"任意一个"员工工资的员工。

显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门
的员工)

(3)多列子查询

单行子查询是指子查询只返回单列,单行数据;

多行子查询是指返回单列多行数据,都是针对单列而言的,而多列子查询则是指查询返回多个列数据的子查询语句

查询和SMITH的部门和岗位完全相同的所有雇员的员工信息,不含SMITH本人

子查询返回了两列(DEPTNO 和 JOB),外层用 (列1, 列2) = (子查询) 进行比较,找出与 SMITH 部门相同、职位相同的其他员工

(4)在from子句中使用子查询

当子查询出现在 FROM 子句中时,它被当作一张临时的"派生表"(Derived Table)来使用。

技巧本质:把子查询的查询结果,在逻辑上视为一张临时存在的表,外层查询可以像操作普通表一样操作它。

练习:显示每个高于自己部门平均工资的员工的姓名、部门、工资、平均工资

获取各个部门的平均工资,将其看作临时表

扩展:显示他们的所在部门的城市位置和部门编号。


查找每个部门工资最高的人的员工信息

查找每个部门工资最高的人的姓名、工资、部门、最高工资


显示每个部门的信息(部门名,编号,地址)和人员数量

方法1:使用多表

多表查询的本质指导思想

  1. 核心目标:将多表问题转化为单表问题。

  2. 核心方法

    • 通过 连接条件(JOIN / WHERE) 将多张表合并成一张逻辑上的"大宽表"

    • 或通过 子查询 先构建临时结果集

  3. 后续操作 :一旦临时表形成,后续的 SELECTWHEREGROUP BYORDER BY 等操作,全部与单表查询完全一致。

  4. 本质理解 :无论多表查询多复杂,最终都可以理解为先构建一张临时单表,然后对它做标准查询

方法2:使用子查询

1. 对EMP表进行人员统计

2. 将上面的表看作临时表

5.合并查询

在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union ,union all

union(已经去重)

该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行。

将工资大于25000或职位是MANAGER的人找出来

union all(没有去重)

该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行

将工资大于 2500 或职位是 MANAGER 的人找出来

UNION / UNION ALL 使用前提

  1. 列数必须相同

  2. 对应列的数据类型兼容

  3. 列的顺序按位置匹配(不是按列名)

  4. 最终列名以第一个 SELECT 为准

6.单行 ,多行 ,多列 子查询区别

对比维度 单行子查询 多行子查询 多列子查询
划分依据 返回行数 返回行数 返回列数
返回特点 返回 1 行 返回 多行(0~n行) 返回 多列(≥2列)
允许返回列数 1列或多列 1列或多列 2列或以上
使用运算符 = > < >= <= <> IN ANY ALL EXISTS =IN(与行数配合)
左侧写法 WHERE 列WHERE (列1,列2) WHERE 列WHERE (列1,列2) WHERE (列1,列2,...)
常见错误 子查询返回多行会报错 NOT INNULL 结果为空 左侧列数与子查询列数不匹配
示例 WHERE sal > (SELECT AVG(sal) FROM EMP) WHERE sal IN (SELECT sal FROM EMP WHERE deptno=30) WHERE (deptno,job) = (SELECT deptno,job FROM EMP WHERE ename='SMITH')
相关推荐
睡不醒男孩0308232 小时前
PostgreSQL 高可用怎么做?我为什么选择了 CLup
数据库·postgresql
正在走向自律2 小时前
标量子查询消除这事儿,我琢磨了三个晚上
数据库
better_liang2 小时前
每日Java面试场景题知识点之-数据库与缓存的一致性
java·数据库·redis·面试·分布式系统·缓存一致性·cache aside
light blue bird2 小时前
工序路径主子表单工序组装图表组件
前端·数据库·信息可视化·.net·web端·razor page
我叫张小白。2 小时前
基于Redis与FastAPI的分布式共享会话体系
数据库·redis·分布式·缓存·中间件·fastapi·依赖注入
java_cj2 小时前
MySQL 8.0新特性详解:从隐藏索引到窗口函数全面解析
数据库·mysql·架构·开源
数据库安全2 小时前
业务可用、数据可控:美创“动态脱敏+数据库透明加密“合规方案
数据库
Wonderful U2 小时前
AI智能日志异常检测告警平台:告别人工排查,秒级定位线上故障
数据库·人工智能·python·django
天河归来2 小时前
国产数据库安全可靠测评产品观察:从集中式、分布式到 HTAP 的发展趋势
数据库·分布式