MySQL中的复合查询使用解读
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">一、先回顾:单表查询的基础操作(以EMP表为例)</a></li><ul class="second_class_ul"><li><a href="#_lab2_0_0">1. 带条件的筛选</a></li><li><a href="#_lab2_0_1">2. 排序与计算字段</a></li><ul class="third_class_ul"><li><a href="#_label3_0_1_0">(1)按部门号升序、工资降序排列</a></li><li><a href="#_label3_0_1_1">(2)计算年薪(工资 ×12 + 奖金,奖金为空则按 0 算)并排序</a></li></ul><li><a href="#_lab2_0_2">3. 聚合与分组查询</a></li><ul class="third_class_ul"><li><a href="#_label3_0_2_2">(1)查每个部门的平均工资、最高工资</a></li><li><a href="#_label3_0_2_3">(2)筛选平均工资 < 2000的部门</a></li></ul></ul><li><a href="#_label1">二、多表查询:跨表关联数据</a></li><ul class="second_class_ul"><li><a href="#_lab2_1_3">DEPT部门表</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_1_4">SALGRADE工资级别表</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_1_5">1. 基础多表联查(等值连接)</a></li><ul class="third_class_ul"><li><a href="#_label3_1_5_4">(1)查 “员工名、工资、所属部门名”</a></li><li><a href="#_label3_1_5_5">(2)限定部门号为 10的员工</a></li></ul><li><a href="#_lab2_1_6">2. 三表联查(含工资级别表)</a></li><ul class="third_class_ul"></ul></ul><li><a href="#_label2">三、自连接:同一张表查上下级</a></li><ul class="second_class_ul"></ul><li><a href="#_label3">四、子查询:用查询结果当条件 / 临时表</a></li><ul class="second_class_ul"><li><a href="#_lab2_3_7">1. 单行子查询(返回一条结果)</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_3_8">2. 多行子查询(返回多条结果)</a></li><ul class="third_class_ul"><li><a href="#_label3_3_8_6">(1)查 “和 10 号部门岗位相同、但不属于 10 号部门” 的员工</a></li><li><a href="#_label3_3_8_7">(2)查 “工资比 30 号部门所有员工都高” 的员工</a></li></ul><li><a href="#_lab2_3_9">3. from 子句子查询(把子查询当临时表)</a></li><ul class="third_class_ul"></ul></ul><li><a href="#_label4">五、合并查询:union/union all</a></li><ul class="second_class_ul"><li><a href="#_lab2_4_10">1. union(自动去重)</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_4_11">2. union all(保留重复)</a></li><ul class="third_class_ul"></ul></ul><li><a href="#_label5">总结</a></li><ul class="second_class_ul"></ul></ul></div><p>在实际开发中,仅用单表查询显然无法满足复杂业务需求。今天我们就以经典的员工管理系统(<code>EMP</code>员工表、<code>DEPT</code>部门表、<code>SALGRADE</code>工资级别表)为例,聊聊 MySQL 复合查询的核心玩法 —— 从单表查询到多表联查、子查询,再到合并查询,每一步都附上真实查询结果,帮你直观理解。</p><p class="maodian"><a name="_label0"></a></p><h2>一、先回顾:单表查询的基础操作(以EMP表为例)</h2>
<p>先明确<code>EMP</code>表基础数据(对应图片中表内容):</p>
<table><thead><tr><th>empno</th><th>ename</th><th>job</th><th>mgr</th><th>hiredate</th><th>sal</th><th>comm</th><th>deptno</th></tr></thead><tbody><tr><td>7369</td><td>SMITH</td><td>CLERK</td><td>7902</td><td>1980-12-17</td><td>800</td><td>NULL</td><td>20</td></tr><tr><td>7499</td><td>ALLEN</td><td>SALESMAN</td><td>7698</td><td>1981-02-20</td><td>1600</td><td>300</td><td>30</td></tr><tr><td>7521</td><td>WARD</td><td>SALESMAN</td><td>7698</td><td>1981-02-22</td><td>1250</td><td>500</td><td>30</td></tr><tr><td>7566</td><td>JONES</td><td>MANAGER</td><td>7839</td><td>1981-04-02</td><td>2975</td><td>NULL</td><td>20</td></tr><tr><td>7654</td><td>MARTIN</td><td>SALESMAN</td><td>7698</td><td>1981-09-28</td><td>1250</td><td>1400</td><td>30</td></tr><tr><td>7698</td><td>BLAKE</td><td>MANAGER</td><td>7839</td><td>1981-05-01</td><td>2850</td><td>NULL</td><td>30</td></tr><tr><td>7782</td><td>CLARK</td><td>MANAGER</td><td>7839</td><td>1981-06-09</td><td>2450</td><td>NULL</td><td>10</td></tr><tr><td>7788</td><td>SCOTT</td><td>ANALYST</td><td>7566</td><td>1987-04-19</td><td>3000</td><td>NULL</td><td>20</td></tr><tr><td>7839</td><td>KING</td><td>PRESIDENT</td><td>NULL</td><td>1981-11-17</td><td>5000</td><td>NULL</td><td>10</td></tr><tr><td>7844</td><td>TURNER</td><td>SALESMAN</td><td>7698</td><td>1981-09-08</td><td>1500</td><td>0</td><td>30</td></tr><tr><td>7876</td><td>ADAMS</td><td>CLERK</td><td>7788</td><td>1987-05-23</td><td>1100</td><td>NULL</td><td>20</td></tr><tr><td>7900</td><td>JAMES</td><td>CLERK</td><td>7698</td><td>1981-12-03</td><td>950</td><td>NULL</td><td>30</td></tr><tr><td>7902</td><td>FORD</td><td>ANALYST</td><td>7566</td><td>1981-12-03</td><td>3000</td><td>NULL</td><td>20</td></tr><tr><td>7934</td><td>MILLER</td><td>CLERK</td><td>7782</td><td>1982-01-23</td><td>1300</td><td>NULL</td><td>10</td></tr></tbody></table>
<p class="maodian"><a name="_lab2_0_0"></a></p><h3>1. 带条件的筛选</h3>
<div class="jb51code"><pre class="brush:sql;">SELECT * FROM EMP
WHERE (sal>500 OR job='MANAGER')
AND ename LIKE 'J%';
</pre></div>
<p><strong>查询结果</strong>:</p>
<table><thead><tr><th>empno</th><th>ename</th><th>job</th><th>mgr</th><th>hiredate</th><th>sal</th><th>comm</th><th>deptno</th></tr></thead><tbody><tr><td>7566</td><td>JONES</td><td>MANAGER</td><td>7839</td><td>1981-04-02</td><td>2975</td><td>NULL</td><td>20</td></tr><tr><td>7900</td><td>JAMES</td><td>CLERK</td><td>7698</td><td>1981-12-03</td><td>950</td><td>NULL</td><td>30</td></tr></tbody></table>
<p class="maodian"><a name="_lab2_0_1"></a></p><h3>2. 排序与计算字段</h3>
<p class="maodian"><a name="_label3_0_1_0"></a></p><h4>(1)按部门号升序、工资降序排列</h4>
<div class="jb51code"><pre class="brush:sql;">SELECT * FROM EMP
ORDER BY deptno, sal DESC;
</pre></div>
<p><strong>查询结果</strong>(节选核心字段):</p>
<table><thead><tr><th>empno</th><th>ename</th><th>sal</th><th>deptno</th></tr></thead><tbody><tr><td>7839</td><td>KING</td><td>5000</td><td>10</td></tr><tr><td>7782</td><td>CLARK</td><td>2450</td><td>10</td></tr><tr><td>7934</td><td>MILLER</td><td>1300</td><td>10</td></tr><tr><td>7788</td><td>SCOTT</td><td>3000</td><td>20</td></tr><tr><td>7902</td><td>FORD</td><td>3000</td><td>20</td></tr><tr><td>7566</td><td>JONES</td><td>2975</td><td>20</td></tr><tr><td>7876</td><td>ADAMS</td><td>1100</td><td>20</td></tr><tr><td>7369</td><td>SMITH</td><td>800</td><td>20</td></tr><tr><td>7698</td><td>BLAKE</td><td>2850</td><td>30</td></tr><tr><td>7499</td><td>ALLEN</td><td>1600</td><td>30</td></tr><tr><td>7844</td><td>TURNER</td><td>1500</td><td>30</td></tr><tr><td>7521</td><td>WARD</td><td>1250</td><td>30</td></tr><tr><td>7654</td><td>MARTIN</td><td>1250</td><td>30</td></tr><tr><td>7900</td><td>JAMES</td><td>950</td><td>30</td></tr></tbody></table>
<p class="maodian"><a name="_label3_0_1_1"></a></p><h4>(2)计算年薪(工资 ×12 + 奖金,奖金为空则按 0 算)并排序</h4>
<div class="jb51code"><pre class="brush:sql;">SELECT ename, sal*12+IFNULL(comm,0) AS '年薪'
FROM EMP
ORDER BY 年薪 DESC;
</pre></div>
<p><strong>查询结果</strong>:</p>
<table><thead><tr><th>ename</th><th>年薪</th></tr></thead><tbody><tr><td>KING</td><td>60000</td></tr><tr><td>SCOTT</td><td>36000</td></tr><tr><td>FORD</td><td>36000</td></tr><tr><td>JONES</td><td>35700</td></tr><tr><td>BLAKE</td><td>34200</td></tr><tr><td>CLARK</td><td>29400</td></tr><tr><td>ALLEN</td><td>19500</td></tr><tr><td>TURNER</td><td>18000</td></tr><tr><td>MARTIN</td><td>16400</td></tr><tr><td>MILLER</td><td>15600</td></tr><tr><td>WARD</td><td>15500</td></tr><tr><td>ADAMS</td><td>13200</td></tr><tr><td>JAMES</td><td>11400</td></tr><tr><td>SMITH</td><td>9600</td></tr></tbody></table>
<p class="maodian"><a name="_lab2_0_2"></a></p><h3>3. 聚合与分组查询</h3>
<p class="maodian"><a name="_label3_0_2_2"></a></p><h4>(1)查每个部门的平均工资、最高工资</h4>
<div class="jb51code"><pre class="brush:sql;">SELECT deptno, FORMAT(AVG(sal),2) AS avg_sal, MAX(sal) AS max_sal
FROM EMP
GROUP BY deptno;
</pre></div>
<p><strong>查询结果</strong>:</p>
<table><thead><tr><th>deptno</th><th>avg_sal</th><th>max_sal</th></tr></thead><tbody><tr><td>10</td><td>2,916.67</td><td>5000</td></tr><tr><td>20</td><td>2,175.00</td><td>3000</td></tr><tr><td>30</td><td>1,566.67</td><td>2850</td></tr></tbody></table>
<p class="maodian"><a name="_label3_0_2_3"></a></p><h4>(2)筛选平均工资 < 2000的部门</h4>
<div class="jb51code"><pre class="brush:sql;">SELECT deptno, AVG(sal) AS avg_sal
FROM EMP
GROUP BY deptno
HAVING avg_sal<2000;
</pre></div>
<p><strong>查询结果</strong>:</p>
<table><thead><tr><th>deptno</th><th>avg_sal</th></tr></thead><tbody><tr><td>30</td><td>1566.6667</td></tr></tbody></table>
<p class="maodian"><a name="_label1"></a></p><h2>二、多表查询:跨表关联数据</h2>
<p>先明确关联表基础数据:</p>
<p class="maodian"><a name="_lab2_1_3"></a></p><h3>DEPT部门表</h3>
<table><thead><tr><th>deptno</th><th>dname</th><th>loc</th></tr></thead><tbody><tr><td>10</td><td>ACCOUNTING</td><td>NEW YORK</td></tr><tr><td>20</td><td>RESEARCH</td><td>DALLAS</td></tr><tr><td>30</td><td>SALES</td><td>CHICAGO</td></tr><tr><td>40</td><td>OPERATIONS</td><td>BOSTON</td></tr></tbody></table>
<p class="maodian"><a name="_lab2_1_4"></a></p><h3>SALGRADE工资级别表</h3>
<table><thead><tr><th>grade</th><th>losal</th><th>hisal</th></tr></thead><tbody><tr><td>1</td><td>700</td><td>1200</td></tr><tr><td>2</td><td>1201</td><td>1400</td></tr><tr><td>3</td><td>1401</td><td>2000</td></tr><tr><td>4</td><td>2001</td><td>3000</td></tr><tr><td>5</td><td>3001</td><td>9999</td></tr></tbody></table>
<p class="maodian"><a name="_lab2_1_5"></a></p><h3>1. 基础多表联查(等值连接)</h3>
<p class="maodian"><a name="_label3_1_5_4"></a></p><h4>(1)查 “员工名、工资、所属部门名”</h4>
<div class="jb51code"><pre class="brush:sql;">SELECT EMP.ename, EMP.sal, DEPT.dname
FROM EMP, DEPT
WHERE EMP.deptno = DEPT.deptno;
</pre></div>
<p><strong>查询结果</strong>(节选):</p>
<table><thead><tr><th>ename</th><th>sal</th><th>dname</th></tr></thead><tbody><tr><td>SMITH</td><td>800</td><td>RESEARCH</td></tr><tr><td>ALLEN</td><td>1600</td><td>SALES</td></tr><tr><td>WARD</td><td>1250</td><td>SALES</td></tr><tr><td>JONES</td><td>2975</td><td>RESEARCH</td></tr><tr><td>MARTIN</td><td>1250</td><td>SALES</td></tr><tr><td>BLAKE</td><td>2850</td><td>SALES</td></tr><tr><td>CLARK</td><td>2450</td><td>ACCOUNTING</td></tr><tr><td>SCOTT</td><td>3000</td><td>RESEARCH</td></tr><tr><td>KING</td><td>5000</td><td>ACCOUNTING</td></tr><tr><td>TURNER</td><td>1500</td><td>SALES</td></tr><tr><td>ADAMS</td><td>1100</td><td>RESEARCH</td></tr><tr><td>JAMES</td><td>950</td><td>SALES</td></tr><tr><td>FORD</td><td>3000</td><td>RESEARCH</td></tr><tr><td>MILLER</td><td>1300</td><td>ACCOUNTING</td></tr></tbody></table>
<p class="maodian"><a name="_label3_1_5_5"></a></p><h4>(2)限定部门号为 10的员工</h4>
<div class="jb51code"><pre class="brush:sql;">SELECT ename, sal, dname
FROM EMP, DEPT
WHERE EMP.deptno=DEPT.deptno
AND DEPT.deptno=10;
</pre></div>
<p><strong>查询结果</strong>:</p>
<table><thead><tr><th>ename</th><th>sal</th><th>dname</th></tr></thead><tbody><tr><td>CLARK</td><td>2450</td><td>ACCOUNTING</td></tr><tr><td>KING</td><td>5000</td><td>ACCOUNTING</td></tr><tr><td>MILLER</td><td>1300</td><td>ACCOUNTING</td></tr></tbody></table>
<p class="maodian"><a name="_lab2_1_6"></a></p><h3>2. 三表联查(含工资级别表)</h3>
<div class="jb51code"><pre class="brush:sql;">SELECT ename, sal, grade
FROM EMP, SALGRADE
WHERE EMP.sal BETWEEN losal AND hisal;
</pre></div>
<p><strong>查询结果</strong>:</p>
<table><thead><tr><th>ename</th><th>sal</th><th>grade</th></tr></thead><tbody><tr><td>SMITH</td><td>800</td><td>1</td></tr><tr><td>ALLEN</td><td>1600</td><td>3</td></tr><tr><td>WARD</td><td>1250</td><td>2</td></tr><tr><td>JONES</td><td>2975</td><td>4</td></tr><tr><td>MARTIN</td><td>1250</td><td>2</td></tr><tr><td>BLAKE</td><td>2850</td><td>4</td></tr><tr><td>CLARK</td><td>2450</td><td>4</td></tr><tr><td>SCOTT</td><td>3000</td><td>4</td></tr><tr><td>KING</td><td>5000</td><td>5</td></tr><tr><td>TURNER</td><td>1500</td><td>3</td></tr><tr><td>ADAMS</td><td>1100</td><td>1</td></tr><tr><td>JAMES</td><td>950</td><td>1</td></tr><tr><td>FORD</td><td>3000</td><td>4</td></tr><tr><td>MILLER</td><td>1300</td><td>2</td></tr></tbody></table>
<p class="maodian"><a name="_label2"></a></p><h2>三、自连接:同一张表查上下级</h2>
<div class="jb51code"><pre class="brush:sql;">-- 别名leader代表领导,worker代表员工
SELECT leader.empno, leader.ename
FROM emp leader, emp worker
WHERE leader.empno = worker.mgr
AND worker.ename='FORD';
</pre></div>
<p><strong>查询结果</strong>:</p>
<table><thead><tr><th>empno</th><th>ename</th></tr></thead><tbody><tr><td>7566</td><td>JONES</td></tr></tbody></table>
<p class="maodian"><a name="_label3"></a></p><h2>四、子查询:用查询结果当条件 / 临时表</h2>
<p class="maodian"><a name="_lab2_3_7"></a></p><h3>1. 单行子查询(返回一条结果)</h3>
<div class="jb51code"><pre class="brush:sql;">SELECT ename, job
FROM EMP
WHERE sal = (SELECT MAX(sal) FROM EMP);
</pre></div>
<p><strong>查询结果</strong>:</p>
<table><thead><tr><th>ename</th><th>job</th></tr></thead><tbody><tr><td>KING</td><td>PRESIDENT</td></tr></tbody></table>
<p class="maodian"><a name="_lab2_3_8"></a></p><h3>2. 多行子查询(返回多条结果)</h3>
<p class="maodian"><a name="_label3_3_8_6"></a></p><h4>(1)查 “和 10 号部门岗位相同、但不属于 10 号部门” 的员工</h4>
<div class="jb51code"><pre class="brush:sql;">SELECT ename,job,sal,deptno
FROM emp
WHERE job IN (SELECT DISTINCT job FROM emp WHERE deptno=10)
AND deptno<>10;
</pre></div>
<p><strong>查询结果</strong>:</p>
<table><thead><tr><th>ename</th><th>job</th><th>sal</th><th>deptno</th></tr></thead><tbody><tr><td>JONES</td><td>MANAGER</td><td>2975</td><td>20</td></tr><tr><td>BLAKE</td><td>MANAGER</td><td>2850</td><td>30</td></tr><tr><td>SMITH</td><td>CLERK</td><td>800</td><td>20</td></tr><tr><td>ADAMS</td><td>CLERK</td><td>1100</td><td>20</td></tr><tr><td>JAMES</td><td>CLERK</td><td>950</td><td>30</td></tr></tbody></table>
<p class="maodian"><a name="_label3_3_8_7"></a></p><h4>(2)查 “工资比 30 号部门所有员工都高” 的员工</h4>
<div class="jb51code"><pre class="brush:sql;">SELECT ename, sal, deptno
FROM EMP
WHERE sal > ALL(SELECT sal FROM EMP WHERE deptno=30);
</pre></div>
<p><strong>查询结果</strong>:</p>
<table><thead><tr><th>ename</th><th>sal</th><th>deptno</th></tr></thead><tbody><tr><td>JONES</td><td>2975</td><td>20</td></tr><tr><td>SCOTT</td><td>3000</td><td>20</td></tr><tr><td>KING</td><td>5000</td><td>10</td></tr><tr><td>FORD</td><td>3000</td><td>20</td></tr></tbody></table>
<p class="maodian"><a name="_lab2_3_9"></a></p><h3>3. from 子句子查询(把子查询当临时表)</h3>
<div class="jb51code"><pre class="brush:sql;">-- 先查各部门平均工资(临时表tmp),再关联员工表
SELECT ename, deptno, sal, FORMAT(tmp.avg_sal,2) AS dept_avg_sal
FROM EMP,
(SELECT AVG(sal) avg_sal, deptno dt FROM EMP GROUP BY deptno) tmp
WHERE EMP.sal > tmp.avg_sal
AND EMP.deptno=tmp.dt;
</pre></div>
<p><strong>查询结果</strong>:</p>
<table><thead><tr><th>ename</th><th>deptno</th><th>sal</th><th>dept_avg_sal</th></tr></thead><tbody><tr><td>KING</td><td>10</td><td>5000</td><td>2,916.67</td></tr><tr><td>JONES</td><td>20</td><td>2975</td><td>2,175.00</td></tr><tr><td>SCOTT</td><td>20</td><td>3000</td><td>2,175.00</td></tr><tr><td>FORD</td><td>20</td><td>3000</td><td>2,175.00</td></tr><tr><td>BLAKE</td><td>30</td><td>2850</td><td>1,566.67</td></tr><tr><td>ALLEN</td><td>30</td><td>1600</td><td>1,566.67</td></tr></tbody></table>
<p class="maodian"><a name="_label4"></a></p><h2>五、合并查询:union/union all</h2>
<p class="maodian"><a name="_lab2_4_10"></a></p><h3>1. union(自动去重)</h3>
<div class="jb51code"><pre class="brush:sql;">SELECT ename, sal, job FROM EMP WHERE sal>2500
UNION
SELECT ename, sal, job FROM EMP WHERE job='MANAGER';
</pre></div>
<p><strong>查询结果</strong>(无重复数据):</p>
<table><thead><tr><th>ename</th><th>sal</th><th>job</th></tr></thead><tbody><tr><td>JONES</td><td>2975</td><td>MANAGER</td></tr><tr><td>BLAKE</td><td>2850</td><td>MANAGER</td></tr><tr><td>SCOTT</td><td>3000</td><td>ANALYST</td></tr><tr><td>KING</td><td>5000</td><td>PRESIDENT</td></tr><tr><td>FORD</td><td>3000</td><td>ANALYST</td></tr><tr><td>CLARK</td><td>2450</td><td>MANAGER</td></tr></tbody></table>
<p class="maodian"><a name="_lab2_4_11"></a></p><h3>2. union all(保留重复)</h3>
<div class="jb51code"><pre class="brush:sql;">SELECT ename, sal, job FROM EMP WHERE sal>2500
UNION ALL
SELECT ename, sal, job FROM EMP WHERE job='MANAGER';
</pre></div>
<p><strong>查询结果</strong>(JONES、BLAKE 重复出现):</p>
<table><thead><tr><th>ename</th><th>sal</th><th>job</th></tr></thead><tbody><tr><td>JONES</td><td>2975</td><td>MANAGER</td></tr><tr><td>BLAKE</td><td>2850</td><td>MANAGER</td></tr><tr><td>SCOTT</td><td>3000</td><td>ANALYST</td></tr><tr><td>KING</td><td>5000</td><td>PRESIDENT</td></tr><tr><td>FORD</td><td>3000</td><td>ANALYST</td></tr><tr><td>JONES</td><td>2975</td><td>MANAGER</td></tr><tr><td>BLAKE</td><td>2850</td><td>MANAGER</td></tr><tr><td>CLARK</td><td>2450</td><td>MANAGER</td></tr></tbody></table>
<p class="maodian"><a name="_label5"></a></p><h2>总结</h2>
<p>MySQL 复合查询是实际开发的核心技能,核心是<strong>理清表关系、灵活组合单表 / 多表 / 子查询语法</strong>。</p>
<p>本文所有示例均基于真实员工管理表数据,查询结果可直接验证,建议你复制 SQL 语句在本地数据库中实操,更快掌握各类查询技巧~</p>
<p>这些仅为个人经验,希望能给大家一个参考,也希望大家多多支持琼殿技术社区。</p>
頁:
[1]