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

08.MySQL复合查询详解

08.MySQL复合查询详解

基本查询回顾

多表查询

自连接

子查询

单行子查询

多行子查询

多列子查询

在FROM子句中使用子查询

合并查询


MySQL复合查询详解

基本查询回顾

在正式进入复合查询之前,先简单回顾一下MySQL的基本查询操作。假设我们有三张表:员工表(emp)、部门表(dept)和工资等级表(salgrade)。这些表的结构和数据如下:

员工表(emp

empnoenamejobmgrhiredatesalcommdeptno
7369SMITHCLERK79021980-12-17800NULL20
7499ALLENSALESMAN76981981-02-20160030030

部门表(dept

deptnodnameloc
10ACCOUNTINGNEW YORK
20RESEARCHDALLAS

工资等级表(salgrade

gradelosalhisal
17001200
212011400

基本查询通常围绕单张表展开,比如筛选特定条件的记录、排序、分组统计等。例如:

  • 查询工资高于500或岗位为MANAGER的员工,并且要求姓名首字母为大写J
    SELECT ename, sal, job 
    FROM emp 
    WHERE (sal > 500 OR job = 'MANAGER') AND ename LIKE 'J%';
    
  • 按部门号升序、工资降序显示员工信息:
    SELECT ename, deptno, sal 
    FROM emp 
    ORDER BY deptno ASC, sal DESC;
    
  • 查询年薪最高的员工:
    SELECT ename, sal*12 + IFNULL(comm, 0) AS annual_salary 
    FROM emp 
    ORDER BY annual_salary DESC 
    LIMIT 1;
    

这些基础查询为后续的复合查询奠定了基础。接下来我们将深入探讨多表关联、自连接、子查询等高级查询技巧。


多表查询

为什么需要多表查询?

现实中的数据往往分散在多个表中。例如,员工信息存储在emp表中,部门信息存储在dept表中,而工资等级信息则在salsgrade表中。如果需要查询某个员工的部门名称或工资等级,就必须将这些表关联起来。

笛卡尔积:多表查询的起点

多表查询的本质是对多张表取笛卡尔积,即所有记录的组合。例如:

SELECT * FROM emp, dept;

这条语句会返回emp表和dept表的笛卡尔积,结果中每一行都是emp的一条记录与dept的一条记录的组合。然而,这种组合大多是无意义的,因此需要通过WHERE子句过滤出有效数据。

笛卡尔积的初步过滤

以查询部门号为10的员工信息为例:

SELECT d.dname, e.ename, e.sal 
FROM emp e, dept d 
WHERE e.deptno = d.deptno AND e.deptno = 10;

这里的关键是e.deptno = d.deptno,它确保了只有员工所在部门与部门表中的记录匹配时才会被选中。

经典案例:查询员工的工资等级

要显示每个员工的姓名、工资和对应的工资等级,需要关联empsalsgrade表:

SELECT e.ename, e.sal, s.grade 
FROM emp e, salgrade s 
WHERE e.sal BETWEEN s.losal AND s.hisal;

这里的BETWEEN条件确保工资落在某个等级的范围内。


自连接

什么是自连接?

自连接是指同一张表与自身进行关联查询。例如,员工表中的mgr字段表示上级领导的编号,而领导本身也是员工,因此可以通过自连接查询员工的领导信息。

案例:查询员工FORD的上级领导

SELECT e1.ename AS employee, e2.ename AS manager 
FROM emp e1, emp e2 
WHERE e1.mgr = e2.empno AND e1.ename = 'FORD';

这里通过给emp表起两个别名e1e2,分别代表员工和领导。e1.mgr = e2.empno确保员工的领导编号与领导的员工编号匹配。


子查询

子查询是嵌套在其他SQL语句中的查询,常用于动态获取条件值。子查询可分为单行子查询、多行子查询、多列子查询等。

单行子查询

单行子查询返回单个值。例如,查询SMITH所在部门的其他员工:

SELECT ename, job, sal, deptno 
FROM emp 
WHERE deptno = (SELECT deptno FROM emp WHERE ename = 'SMITH') AND ename != 'SMITH';

子查询(SELECT deptno FROM emp WHERE ename = 'SMITH')先获取SMITH的部门号,然后外层查询筛选出同一部门的其他员工。

多行子查询

多行子查询返回多行单列数据,常与INALLANY等关键字配合使用。

使用IN筛选多行结果

查询与10号部门岗位相同的员工(不包括10号部门本身):

SELECT ename, job, sal, deptno 
FROM emp 
WHERE job IN (SELECT DISTINCT job FROM emp WHERE deptno = 10) AND deptno != 10;

子查询SELECT DISTINCT job FROM emp WHERE deptno = 10先获取10号部门的所有岗位,外层查询通过IN筛选出这些岗位的员工。

使用ALLANY比较多行结果
  • 查询工资高于30号部门所有员工的员工:
    SELECT ename, sal, deptno 
    FROM emp 
    WHERE sal > ALL(SELECT sal FROM emp WHERE deptno = 30);
    
  • 查询工资高于30号部门任意员工的员工:
    SELECT ename, sal, deptno 
    FROM emp 
    WHERE sal > ANY(SELECT sal FROM emp WHERE deptno = 30);
    

多列子查询

多列子查询返回多列数据,通常用于比较多个字段。例如,查询与SMITH部门和岗位完全相同的员工:

SELECT ename, deptno, job 
FROM emp 
WHERE (deptno, job) = (SELECT deptno, job FROM emp WHERE ename = 'SMITH') AND ename != 'SMITH';

在FROM子句中使用子查询

子查询不仅可以出现在WHERE子句中,还可以作为临时表嵌套在FROM子句中。例如,查询每个部门工资高于平均工资的员工:

SELECT e.ename, e.deptno, e.sal, tmp.avg_sal 
FROM emp e, 
(SELECT deptno, AVG(sal) AS avg_sal FROM emp GROUP BY deptno) tmp 
WHERE e.deptno = tmp.deptno AND e.sal > tmp.avg_sal;

这里子查询tmp先计算每个部门的平均工资,外层查询通过关联emptmp筛选出符合条件的员工。


合并查询

合并查询通过UNIONUNION ALL将多个查询结果合并。

UNIONUNION ALL的区别

  • UNION:合并结果并去重。
  • UNION ALL:合并结果但不去重。

案例:查询工资大于2500或职位为MANAGER的员工

SELECT * FROM emp WHERE sal > 2500 
UNION 
SELECT * FROM emp WHERE job = 'MANAGER';

等价于:

SELECT * FROM emp WHERE sal > 2500 OR job = 'MANAGER';

但使用UNION可以更清晰地拆分查询逻辑。


综合案例:查询每个部门的最高工资员工

方法一:子查询+多表查询

SELECT e.ename, e.deptno, e.sal, tmp.max_sal 
FROM emp e, 
(SELECT deptno, MAX(sal) AS max_sal FROM emp GROUP BY deptno) tmp 
WHERE e.deptno = tmp.deptno AND e.sal = tmp.max_sal;

方法二:自连接

SELECT e1.ename, e1.deptno, e1.sal 
FROM emp e1 
WHERE e1.sal = (SELECT MAX(sal) FROM emp e2 WHERE e1.deptno = e2.deptno);

总结

MySQL的复合查询功能强大,能够处理复杂的业务需求。通过多表关联、自连接、子查询和合并查询,开发者可以灵活地组合数据,实现跨表分析、动态筛选和结果聚合。掌握这些技巧后,即使是面对海量数据,也能高效地提取所需信息。

http://www.lqws.cn/news/94825.html

相关文章:

  • 可视化大屏工具对比:GoView、DataRoom、积木JimuBI、Metabase、DataEase、Apache Superset 与 Grafana
  • LeetCode第244题_最短单词距离II
  • C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
  • Java复习Day26
  • 登高架设作业实操考试需要注意哪些安全细节?
  • Docker 镜像深度剖析:构建、管理与优化
  • 基于langchain的简单RAG的实现
  • AXURE安装+汉化-Windows
  • Axure形状类组件图标库(共8套)
  • jenkins结合gitlab实现CI
  • 详解开漏输出和推挽输出
  • Apache Doris 在数据仓库中的作用与应用实践
  • pikachu靶场通关笔记12 XSS关卡08-XSS之htmlspecialchars(四种方法渗透)
  • 奥威BI+AI数据分析:企业数智化转型的加速器
  • HTTP Error 400 Bad request 问题分析解决
  • 【前端并发请求控制:必要性与实现策略】
  • 如何进行页面前端监控
  • 手摸手还原vue3中reactive的get陷阱以及receiver的作用
  • SpringBoot3.2新特性:JdbcClient
  • web攻防之SSTI 注入漏洞
  • Windows 下部署 SUNA 项目:虚拟环境尝试与最终方案
  • 【从0-1的HTML】第2篇:HTML标签
  • Double/Debiased Machine Learning
  • 从仿射矩阵得到旋转量平移量缩放量
  • 【氮化镓】GaN HMETs器件物理失效分析进展
  • 【Java Web】7.事务管理AOP
  • 下载并运行自制RAG框架
  • PyTorch——线性层及其他层介绍(6)
  • Apache Iceberg 如何实现分布式 ACID 事务:深度解析大数据时代的可靠数据管理
  • Java面试八股--07-项目篇