11 复合查询上

11 复合查询上
小米里的大麦复合查询上
1. 基本查询回顾
首先我们先创建下面的表数据:
1 | mysql> create database Compound_query; |
查询工资高于 500 或岗位为 MANAGER 的雇员,同时还要满足他们的姓名首字母为大写的 J
1 | mysql> select ename,job,sal from emp where (sal > 500 or job = 'MANAGER') and ename like 'J%'; |
按照部门号升序而雇员的工资降序排序
1 | mysql> select * from emp order by deptno asc, sal desc; |
使用年薪进行降序排序
1 | mysql> select *, (sal + ifnull(null,0))*12 as '年薪' from emp order by 年薪 desc; |
显示工资最高的员工的名字和工作岗位
1 | mysql> select ename,job from emp where sal = (select max(sal) from emp); |
显示工资高于平均工资的员工信息
1 | mysql> select * from emp where sal > (select avg(sal) from emp); |
显示每个部门的平均工资和最高工资
1 | mysql> select deptno, avg(sal), max(sal) from emp group by deptno; |
显示平均工资低于 2000 的部门号和它的平均工资
1 | mysql> select deptno, avg(sal) from emp group by deptno having avg(sal) < 2000; |
显示每种岗位的雇员总数,平均工资
1 | mysql> select job, count(*), avg(sal) from emp group by job; |
2. 多表查询
创建另一张表数据:
1 | mysql> create table dept ( |
1. 多表查询概念
多表查询就是从 不止一个表 里查数据,比如要把表 A 和表 B 两个表的数据组合起来看。在进行多表查询时,只需要将多张表的表名依次放到 from 子句之后,用逗号隔开即可,这时 MySQL 将会对给定的这多张表取笛卡尔积,作为多表查询的初始数据源。
2. 笛卡尔积(最简单的多表查询)
笛卡尔积就是最原始、最“野蛮”的多表组合方式:不管两个表有没有关联条件,所有的组合都会组合出来。 其本质就是对给定的多张表取笛卡尔积,然后在笛卡尔积中进行查询。比如:表 A 有 10 行,表 B 有 20 行,那么结果:10 × 20 = 200 行,每行是 A 的每一行与 B 的每一行全组合。
1 | # 笛卡尔积(最基础、最危险的多表查询) |
3. 示例
综合上述,便能得出:
1 | mysql> show tables; |
这个组合 是笛卡尔积 虽然是正确的,但 没有意义,属于无用全组合,仔细观看能发现 deptno 列看起来不太一样:
- emp 表有自己的 deptno(员工所属部门,如 10,20,30)
- dept 表也有 deptno(部门编号,如 10,20,30,40)
- 没有 ON 条件 → 两表的 deptno 独立重复出现,列名相同但内容不匹配,导致输出中 deptno(emp 的)和 deptno(dept 的)并排。
所以:deptno 重复是正常现象,因为两表列名一样却没关联。下一步需要加 JOIN ON 过滤。
4. JOIN ON 过滤
所谓 JOIN ON 过滤,其实就是把笛卡尔积限制成有意义的匹配行,只保留两表满足条件的组合。
JOIN ... ON ...表示联表 + 条件过滤。
- JOIN:把两个表“凑到一起”
- ON:指定 怎么凑(条件)
如果不写
ON,就是笛卡尔积,啥也不管,直接全组合,写了ON,就只凑符合条件的行。
语法:
1 | SELECT 列... FROM 表1 INNER JOIN 表2 ON 表1.字段 = 表2.字段; # INNER 表示内连接,双方都有才显示(后文会讲到) |
1 | mysql> select * from emp e, dept d where e.deptno=d.deptno; # 旧写法(逗号 + WHERE)= 隐式内连接 |
5. 示例
显示部门号为 10 的部门名,员工名和工资
1 | mysql> select dname,ename,sal from emp,dept where emp.deptno = dept.deptno and dept.deptno = 10; |
显示员工姓名、工资及部门名称
1 | mysql> select ename '姓名', sal '工资', dname '部门名称' from emp inner join dept on emp.deptno=dept.deptno; |
显示部门名称、部门地点,以及该部门所有员工的平均工资
1 | # FROM dept d —— 先把 dept 表取个别名叫 d |
3. 自连接
1. 自连接概念
自连接其实就是 自己跟自己联表/同一张表自己连自己,说白了就是:表 A 跟表 A 自己凑在一起查。总之 :一张表里有“指来指去”的字段,就用自连接查关系。
作用:查询表内有层级/关系的数据,比如:
- 员工和他的经理(mgr 指向 empno)
- 上下级部门
- 分类的父子关系
- 最常见的是 上下级、父子、同组的关系。
本质: 还是笛卡尔积 + 过滤,即:自连接 = 笛卡尔积 + 条件过滤。先把表 × 自己(笛卡尔积),再用 ON 条件过滤出有关系的行。
2. 基本语法
1 | SELECT a.列名, b.列名 |
注意事项:
必须给别名: 不给别名,SQL 直接报错,因为它分不清左右两边的“自己”。
INNER 和 LEFT 的区别(看自己想“保谁”):
INNER JOIN(内连接):
- 逻辑: 只有两边都有的,才查出来。
- 例子: 查“有经理的员工”。如果老板没有经理,那老板这行数据 查不到。
LEFT JOIN(左连接):
- 逻辑: 以左边的表为主,左边全都要。右边要是找不到匹配的,就填空(NULL)。
- 例子: 查“所有员工,顺便看看经理是谁”。老板也能查到,只是经理那一栏是空的。
- 别名不能重: 千万别写
FROM 表 a JOIN 表 a,报错警告你。必须写成a和b。 - 条件别漏写: 如果
ON里的条件没写对,或者干脆忘了写,数据库会把表里的每一行都和其他每一行配一遍(笛卡尔积)。本来 100 行,瞬间变 10000 行,数据库容易卡死。 - 别名别搞混: 既然分了 a 和 b,后面查的时候就得说清楚,比如
a.name是员工名,b.name是经理名,别混着写。
3. 示例
查出每位有上司的员工姓名,以及他/她的直属经理姓名
1 | # 查有上司的员工和上司名字:把员工表起别名e,经理表起别名m,通过mgr指向empno连接 |
找出所有“没有直属下属”的员工(即没人汇报给他/她)
1 | # 查没下属的员工 |
显示“经理薪水低于自己下属平均薪水”的经理信息
1 | # 查经理工资低于下属平均的 |














