当前位置: 首页 > 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.xdnf.cn/news/784495.html

相关文章:

  • CAMEL-AI开源自动化任务执行助手OWL一键整合包下载
  • 鸿蒙版Taro 搭建开发环境
  • 74. 搜索二维矩阵 (力扣)
  • React 第五十二节 Router中 useResolvedPath使用详解和注意事项示例
  • 制作一款打飞机游戏64:关卡设计
  • Oracle双平面适用场景讨论会议
  • 技巧小结:外部总线访问FPGA寄存器
  • 互联网三高架构 一
  • 高可靠系统中的线缆屏蔽与接地设计
  • AI超级阅读器:电竞数据的破壁者
  • 面向开发者的提示词工程——导读
  • Blocked aria-hidden on an element because its descendant retained focus.
  • JVM知识
  • 线程池详细解析(三)
  • 报表/报告组件(二)-实例与实现解释
  • pytorch3d+pytorch1.10+MinkowskiEngine安装
  • CSS基础2
  • saveOrUpdate 有个缺点,不会把值赋值为null,解决办法
  • Monorepo 详解:现代前端工程的架构革命
  • Ansys Zemax | 手机镜头设计 - 第 3 部分:使用 STAR 模块和 ZOS-API 进行 STOP 分析
  • Electron 桌面商城开发:攻克多窗口通信、本地存储与内存泄漏实战
  • Linux——初步认识Shell、深刻理解Linux权限
  • 【Redis】笔记|第7节|大厂生产级Redis高并发分布式锁实战(二)
  • 二进制安全-OpenWrt-uBus
  • Ethernet/IP转DeviceNet网关:驱动大型矿山自动化升级的核心纽带
  • Freemarker快速入门
  • Linux 测试本机与192.168.1.130 主机161/udp端口连通性
  • 【办公类-48-04】202506每月电子屏台账汇总成docx-5(问卷星下载5月范围内容,自动获取excel文件名,并转移处理)
  • 【最新版】西陆洗车系统源码全开源+uniapp前端+搭建教程
  • 悟饭游戏厅苹果版(悟饭掌悦)|iOS游戏社区手柄工具