Re:Mysql数据库基础篇(八):详细讲解复合查询、多表查询、自连接、多行、多列子查询与合并查询


◆ 博主名称: 小此方-CSDN博客 大家好,欢迎来到小此方的博客。
⭐️Linux系列个人专栏: 【主题曲】Mysql
⭐️此方的GitHub: github_此方
⭐️ Re系列专栏:我们思考 (Rethink) · 我们重建 (Rebuild) · 我们记录 (Record)


文章目录

  • 概要&序論
  • 一、多表查询与笛卡尔积
    • [1.1 什么是笛卡尔积?](#1.1 什么是笛卡尔积?)
    • [1.2 笛卡尔积的消除:连接条件](#1.2 笛卡尔积的消除:连接条件)
  • 二、自连接
    • [2.1 需求场景](#2.1 需求场景)
    • [2.2 方案一:使用子查询(分步思考)](#2.2 方案一:使用子查询(分步思考))
    • [2.3 方案二:使用多表查询(自连接)](#2.3 方案二:使用多表查询(自连接))
  • 三、子查询:SQL中的嵌套艺术
    • [3.1 单行子查询](#3.1 单行子查询)
    • [3.2 多行子查询](#3.2 多行子查询)
    • [3.3 多列子查询](#3.3 多列子查询)
    • [3.4 在 from 子句中使用子查询](#3.4 在 from 子句中使用子查询)
    • [8.4.5 合并查询](#8.4.5 合并查询)
      • [8.4.5.1 union](#8.4.5.1 union)
      • [8.4.5.3 union all](#8.4.5.3 union all)

概要&序論

  Hello大家好,我是此方,

一、多表查询与笛卡尔积

  实际开发中往往数据来自不同的表,所以需要多表查询。我们以一个简单的公司管理系统为例,假设有三张表:EMP(员工表)、DEPT(部门表)、SALGRADE(工资等级表)来演示如何进行多表查询。

  比如需求是:显示雇员名、雇员工资以及所在部门的名字。因为上面的数据来自 EMP 和 DEPT 表,因此要联合查询。

1.1 什么是笛卡尔积?

  如果直接写 select * from EMP, DEPT;,会发生什么?

  它的底层执行逻辑是:

  1. 从第一张表中选出第一条记录,和第二个表的所有记录进行组合。
  2. 然后再从第一张表取第二条记录,和第二张表中的所有记录组合。
  3. 不加过滤条件,得到的结果称为笛卡尔积。

  由于笛卡尔积会将两张表的记录进行穷举式的全排列,如果 EMP 表有 14 条记录,DEPT 表有 4 条记录,最终会产生 14 * 4 = 56 条记录,其中包含了大量毫无关联的无效数据。

1.2 笛卡尔积的消除:连接条件

  其实我们只要 EMP 表中的 deptno 等于 DEPT 表中的 deptno 字段的记录。通过增加 WHERE 条件,就可以将两张表真正关联起来。

sql 复制代码
select EMP.ename, EMP.sal, DEPT.dname 
from EMP, DEPT 
where EMP.deptno = DEPT.deptno;

二、自连接

  在实际业务中,我们常常会遇到层级关系的数据,比如员工和上级领导。此时,我们需要的数据都在同一张表中,这就需要用到自连接。

  自连接是指在同一张表连接查询。 它的核心思想是把一张表当成两张表来看待,通过给表起不同的别名,让它们自己跟自己进行笛卡尔积和条件过滤。

2.1 需求场景

  案例:显示员工 FORD 的上级领导的编号和姓名。(注意:在 EMP 表中,mgr 字段代表该员工领导的编号,它对应着 empno)。

2.2 方案一:使用子查询(分步思考)

  最直观的想法是分两步走:先查出 FORD 的领导编号,再根据编号查领导的名字。这就是子查询。

sql 复制代码
select empno, ename from emp 
where emp.empno = (
    select mgr from emp where ename = 'FORD'
);

2.3 方案二:使用多表查询(自连接)

  如果要一步到位,就需要用到自连接。我们将 emp 表看作两张表:一张是领导表(别名 leader),一张是员工表(别名 worker)。

  为什么必须起别名?因为要先做笛卡尔积,如果不加别名,数据库就不知道你指的到底是哪张表里的 empno 或 mgr。

sql 复制代码
-- 使用到表的别名
-- from emp leader, emp worker, 给自己的表起别名,因为要先做笛卡尔积,所以别名可以先识别
select leader.empno, leader.ename 
from emp leader, emp worker 
where leader.empno = worker.mgr and worker.ename = 'FORD';

  在这个查询中:

  1. from emp leader, emp worker 构成了笛卡尔积。
  2. leader.empno = worker.mgr 是连接条件,表示领导表里的员工编号等于员工表里的领导编号。
  3. worker.ename = 'FORD' 是过滤条件,锁定我们要找的那个打工人是 FORD。

  通过这种"自己连自己"的方式,完美解决了同表内的层级关联查询。

三、子查询:SQL中的嵌套艺术

  子查询是指嵌入在其他SQL语句中的select语句,也叫嵌套查询。

3.1 单行子查询

  返回一行记录的子查询。

  案例:显示SMITH同一部门的员工。

sql 复制代码
select * from EMP WHERE deptno = (select deptno from EMP where ename='smith');

3.2 多行子查询

  返回多行记录的子查询。

  1. in关键字:查询和10号部门的工作岗位相同的雇员的名字,岗位,工资,部门号,但是不包含10自己的。

sql 复制代码
select ename,job,sal,deptno from emp where job in (select distinct job from emp where deptno=10) and deptno<>10;

  2. all关键字:显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号。

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

  3. any关键字:显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门的员工)。

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

3.3 多列子查询

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

  案例:查询和SMITH的部门和岗位完全相同的所有雇员,不含SMITH本人。

sql 复制代码
mysql> select ename from EMP where (deptno, job)=(select deptno, job from EMP where ename='SMITH') and ename <> 'SMITH';
+--------+
| ename  |
+--------+
| ADAMS  |
+--------+

3.4 在 from 子句中使用子查询

  子查询语句出现在 from 子句中。这里要用到数据查询的技巧,把一个子查询当作一个临时表使用。

  案例1:显示每个高于自己部门平均工资的员工的姓名、部门、工资、平均工资。

sql 复制代码
-- 获取各个部门的平均工资,将其看作临时表
select ename, deptno, sal, format(asal,2) from EMP,
    (select avg(sal) asal, deptno dt from EMP group by deptno) tmp
where EMP.sal > tmp.asal and EMP.deptno=tmp.dt;

  案例2:查找每个部门工资最高的人的姓名、工资、部门、最高工资。

sql 复制代码
select EMP.ename, EMP.sal, EMP.deptno, ms from EMP,
    (select max(sal) ms, deptno from EMP group by deptno) tmp
where EMP.deptno=tmp.deptno and EMP.sal=tmp.ms;

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

  方法1:使用多表。

sql 复制代码
select DEPT.dname, DEPT.deptno, DEPT.loc,count(*) '部门人数' from EMP, DEPT
where EMP.deptno=DEPT.deptno
group by DEPT.deptno,DEPT.dname,DEPT.loc;

  方法2:使用子查询。

sql 复制代码
-- 1. 对 EMP 表进行人员统计
select count(*), deptno from EMP group by deptno;
-- 2. 将上面的表看作临时表
select DEPT.deptno, dname, mycnt, loc from DEPT,
    (select count(*) mycnt, deptno from EMP group by deptno) tmp
where DEPT.deptno=tmp.deptno;

8.4.5 合并查询

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

8.4.5.1 union

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

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

sql 复制代码
mysql> select ename, sal, job from EMP where sal>2500 union
    -> select ename, sal, job from EMP where job='MANAGER'; --去掉了重复记录
+--------+---------+-----------+
| ename  | sal     | job       |
+--------+---------+-----------+
| JONES  | 2975.00 | MANAGER   |
| BLAKE  | 2850.00 | MANAGER   |
| SCOTT  | 3000.00 | ANALYST   |
| KING   | 5000.00 | PRESIDENT |
| FORD   | 3000.00 | ANALYST   |
| CLARK  | 2450.00 | MANAGER   |
+--------+---------+-----------+

8.4.5.3 union all

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

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

sql 复制代码
mysql> select ename, sal, job from EMP where sal>2500 union all
    -> select ename, sal, job from EMP where job='MANAGER';
+--------+---------+-----------+
| ename  | sal     | job       |
+--------+---------+-----------+
| JONES  | 2975.00 | MANAGER   |
| BLAKE  | 2850.00 | MANAGER   |
| SCOTT  | 3000.00 | ANALYST   |
| KING   | 5000.00 | PRESIDENT |
| FORD   | 3000.00 | ANALYST   |
| JONES  | 2975.00 | MANAGER   |
| BLAKE  | 2850.00 | MANAGER   |
| CLARK  | 2450.00 | MANAGER   |
+--------+---------+-----------+

好的本文内容到此结束,我是此方,我们下期再见。

相关推荐
xszivvvv1 小时前
Mariadb数据库frm文件异常,如何恢复数据
数据库·mariadb
smile_life_2 小时前
MySQL 设置 防止账户被暴力破解
数据库·mysql
ShineWinsu2 小时前
对于Qt:QRadioButton常见属性以及QButtonGroup的解析
数据库·c++·qt·microsoft·gui·qradiobutton·qbuttongroup
测试盐2 小时前
oracle数据库卡顿排查
数据库·oracle
滕州市燕猫虎计算机科技工作室个体工商户2 小时前
MySQL、MVCC、多版本并发控制
数据库·mysql·mvcc·数据库事务
明航咨询-陈老师2 小时前
ITSS运行维护服务能力成熟度认证技术纵深:标准模型、等级路径、2026审核趋势与CS/CMMI对比
服务器·数据库·cmmi
缓慢更新3 小时前
AI 辅助生成单测:从接口定义到用例的流水线
java·服务器·前端·网络·数据库·人工智能
AI小百科3 小时前
向量数据库:AI 的「记忆仓库」是怎么工作的
数据库·人工智能·oracle
煎饼皮皮侠4 小时前
【设计】设计一个Web版数据库管理平台(之七):多数据库类型易扩展
数据库