【MySQL 数据库】复合查询

大家好,在 MySQL 日常开发里,单表查询 只能处理最简单的数据需求,真正的业务场景几乎都要用到复合查询------ 也就是多表关联、嵌套查询、自连接、结果合并这类高级查询。

今天这篇文章,我就带着大家把复合查询从基础到实战彻底讲透,每一个知识点都配案例 + 解释,小白也能轻松学会。


一、先回顾:单表基础查询(温故知新)

复合查询是单表查询的进阶,我们先用几个经典案例快速过一遍重点语法。

1. 多条件筛选

查询工资高于 500 岗位是 MANAGER,且姓名以 J 开头的员工:

sql

复制代码
SELECT * FROM EMP 
WHERE (sal>500 OR job='MANAGER') 
AND ename LIKE 'J%';

2. 多字段排序

按部门号升序、同部门内工资降序:

sql

复制代码
SELECT * FROM EMP ORDER BY deptno asc, sal DESC;

3. 计算年薪并排序

奖金为空时用 IFNULL 转 0,避免计算错误:

sql

复制代码
SELECT ename, sal*12+IFNULL(comm,0) AS '年薪' 
FROM EMP 
ORDER BY 年薪 DESC;

4. 聚合函数搭配子查询

  • 查工资最高的员工:

sql

复制代码
SELECT ename, job FROM EMP 
WHERE sal = (SELECT MAX(sal) FROM EMP);
  • 查高于平均工资的员工:

sql

复制代码
SELECT ename, sal FROM EMP 
WHERE sal > (SELECT AVG(sal) FROM EMP);

5. 分组统计 + 分组后过滤

  • 每个部门平均工资(保留两位小数)、最高工资:

sql

复制代码
SELECT deptno, FORMAT(AVG(sal), 2), MAX(sal) 
FROM EMP 
GROUP BY deptno;
  • 这里的FORMAT 是 MySQL 里专门用来「格式化数字 / 日期」的函数,最常用作用是:把数字保留指定位小数、加千分位分隔符。标准格式:FORMAT(数字, 保留小数位数)。

  • 平均工资低于 2000 的部门:

sql

复制代码
SELECT deptno, AVG(sal) AS avg_sal 
FROM EMP 
GROUP BY deptno 
HAVING avg_sal < 2000;

二、多表查询:跨表取数的核心

实际开发中,数据分散在多张表里,必须用多表连接才能拿到完整信息。

本文用经典 3 张表演示:

  • EMP:员工表(员工号、姓名、岗位、工资、部门号...)
  • DEPT:部门表(部门号、部门名、位置...)
  • SALGRADE:工资等级表(等级、最低工资、最高工资)

1. 什么是笛卡尔积

不加连接条件直接查多张表,会出现全组合 ,数据量爆炸,绝对不能用

sql

复制代码
-- 错误示例:产生笛卡尔积
SELECT * FROM EMP, DEPT;

2. 正确多表查询(内连接)

必须加上关联条件(通常是外键 = 主键)。

案例 1:员工名、工资、所在部门名

sql

复制代码
SELECT EMP.ename, EMP.sal, DEPT.dname 
FROM EMP, DEPT 
WHERE EMP.deptno = DEPT.deptno;
案例 2:只看 10 号部门的员工与部门名

sql

复制代码
SELECT ename, sal, dname 
FROM EMP, DEPT 
WHERE EMP.deptno = DEPT.deptno 
AND DEPT.deptno = 10;
案例 3:员工姓名、工资、工资等级

sql

复制代码
SELECT ename, sal, grade 
FROM EMP, SALGRADE 
WHERE EMP.sal BETWEEN losal AND hisal;

三、自连接:一张表自己连自己

自连接 :同一张表起两个别名,当成两张表用。典型场景:员工与领导关系 (员工表的 mgr 指向领导的 empno)。

案例:查员工 FORD 的上级编号与姓名

  • 方式 1:子查询

sql

复制代码
SELECT empno, ename 
FROM emp 
WHERE empno = (SELECT mgr FROM emp WHERE ename='FORD');
  • 方式 2:自连接(更优雅)

sql

复制代码
SELECT leader.empno, leader.ename 
FROM emp leader, emp worker 
WHERE leader.empno = worker.mgr 
AND worker.ename='FORD';

要点:给表起别名,区分 "领导表"leader 和 "员工表"worker。


四、子查询(嵌套查询):复合查询灵魂

子查询 :把一个 SELECT 嵌套在另一个 SQL 里,先执行内层,再执行外层。

1. 单行子查询(返回 1 行 1 列)

用于 = > < >= <= 这类单值比较。

案例:和 SMITH 同一部门的员工

sql

复制代码
SELECT * FROM EMP 
WHERE deptno = (SELECT deptno FROM EMP WHERE ename='SMITH');

2. 多行子查询(返回多行 1 列)

必须搭配 IN / ANY / ALL 使用。

① 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;
② ALL(比所有都...)

工资比 30 部门所有人都高的员工:

sql

复制代码
SELECT ename, sal, deptno 
FROM EMP 
WHERE sal > ALL(SELECT sal FROM EMP WHERE deptno=30);
③ ANY(比任意一个...)

工资比 30 部门任意一人高即可:

sql

复制代码
SELECT ename, sal, deptno 
FROM EMP 
WHERE sal > ANY(SELECT sal FROM EMP WHERE deptno=30);

3. 多列子查询(返回多列)

同时匹配多个字段 ,用 (字段1, 字段2) = (子查询列1, 列2)

案例:和 SMITH 部门、岗位完全相同的人(排除 SMITH):

sql

复制代码
SELECT ename FROM EMP 
WHERE (deptno, job) = (SELECT deptno, job FROM EMP WHERE ename='SMITH') 
AND ename <> 'SMITH';

4. 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:部门信息 + 部门人数

sql

复制代码
SELECT DEPT.deptno, dname, mycnt, loc 
FROM DEPT, 
  (SELECT COUNT(*) mycnt, deptno FROM EMP GROUP BY deptno) tmp 
WHERE DEPT.deptno = tmp.deptno;

五、合并查询:UNION 与 UNION ALL

多个 SELECT 结果纵向拼接,要求:

  • 列数相同
  • 对应列类型兼容
  • 列名以第一个 SELECT 为准

1. UNION:合并并自动去重

sql

复制代码
SELECT ename, sal, job FROM EMP WHERE sal>2500
UNION
SELECT ename, sal, job FROM EMP WHERE job='MANAGER';

2. UNION ALL:直接合并,不去重

性能比 UNION 高很多,确定无重复时优先用它。

sql

复制代码
SELECT ename, sal, job FROM EMP WHERE sal>2500
UNION ALL
SELECT ename, sal, job FROM EMP WHERE job='MANAGER';

对比速记

表格

关键字 是否去重 性能 适用场景
UNION 较低 需去重
UNION ALL 允许重复 / 确定无重复

六、实战 OJ 常考题型(练手必备)

  1. 查找所有员工入职时候的薪水情况_牛客题霸_牛客网
  2. 获取所有非manager的员工emp_no_牛客题霸_牛客网
  3. 获取所有员工当前的manager_牛客题霸_牛客网
  4. 【MySQL牛客】11.获取所有员工当前的manager-CSDN博客

这些题在牛客网非常高频,练完基本面试稳了。


七、复合查询核心总结

  1. 多表查询一定要加连接条件,避免笛卡尔积
  2. 自连接 = 同表起别名,处理层级关系
  3. 子查询分:单行 / 多行 / 多列 / FROM 子查询
  4. IN / ANY / ALL 专门处理多行子查询
  5. UNION 去重,UNION ALL 性能更高
  6. 分组后过滤用 HAVING,不是 WHERE

八、学习建议

  • 先把本文案例手敲一遍
  • EXPLAIN 看执行计划,理解查询原理
  • 多刷牛客 / LeetCode SQL 专题,强化手感

复合查询是 MySQL 最核心、面试最高频的知识点,吃透它,你的 SQL 水平会直接上一个台阶。

相关推荐
夕除1 小时前
spring boot --07
数据库·sql
Elastic 中国社区官方博客1 小时前
Elasticsearch:为 AI Agent builder 创建 skill plugin
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
Data_Journal1 小时前
2026年十大数据集网站
大数据·开发语言·数据库·人工智能·python
用户86022504674721 小时前
Jetpack Activity 完整示例教程
android
珠海西格电力1 小时前
如何实现零碳园区管理系统“云-边-端”架构的协同
大数据·数据库·人工智能·架构·能源
XS0301061 小时前
JDBC实现数据库增删改查
数据库
茉莉玫瑰花茶1 小时前
LangGraph 入门教程:构建 AI 工作流 [ 案例一 ]
数据库
宸凉1 小时前
Oracle 19C的安装
数据库·oracle
simplepeng2 小时前
如何减少 89% 的重组,每个Compose开发者都需要的技巧 - derivedStateOf
android·android jetpack