一、什么是子查询?
子查询(subquery)是指嵌套在另一条 sql 语句中的 select 语句,也叫内层查询。外层包含它的语句叫主查询或外层查询。根据子查询返回结果的"形状",可以分为四种类型:

子查询 = 一条 select 嵌套在另一条 select 内部
- 外面的查询叫 主查询 / 外层查询
- 里面嵌套的查询叫 子查询 / 内层查询
执行顺序:先执行子查询 → 得到结果 → 再把结果交给主查询使用
基本结构:
select 字段列表
from 表名
where 字段 运算符 (
select 字段
from 表名
where 条件
);二、子查询按结果集分类(最重要)
子查询一共分 4 类,你必须全部掌握:
1. 标量子查询(单行单列)
标量子查询:
子查询返回的结果是一个单个值(数字,字符串,日期等),最简单的形式,这种子查询称为 标量子查询。
返回:一个值能用符号:= > < >= <= !=
示例:查询 “研发部” 的所有员工
select emp.*
from emp
where emp.dept_id = (
select dept.id
from dept
where dept.name = '研发部'
);扩展:
any:满足任意一个all:满足全部
返回单个值(1行1列),可以用在任何需要单值的地方,比如 =、>、< 等比较运算符后面。
示例:查询工资高于平均工资的员工
select name, salary
from employees
where salary > (
select avg(salary)
from employees
);内层的 select avg(salary) 只返回一个数字,外层用 > 直接比较。如果子查询返回多行,mysql 会报错。
2.列子查询(column subquery)
返回多行一列,常配合 in、not in、any、all 使用。
示例 1:in — 查询属于某些部门的员工
select name
from employees
where dept_id in (
select id
from departments
where location = '上海'
);示例 2:any — 工资比研发部任意一人高即可
select name
from employees
where salary > any (
select salary from employees where dept_id = 3
);示例 3:all — 工资比研发部所有人都高
select name
from employees
where salary > all (
select salary from employees where dept_id = 3
);any 相当于"至少一个满足",all 相当于"全部都满足"。
-- 查询销售部和市场部的所有员工的信息 select id from dept where name='销售部' or name='市场部'; -- 返回值(2,4) select * from emp33 where id in(2,4) 等价于 select* from emp33 where id in (select id from dept where name='销售部' or name='市场部');
3. 行子查询(单行多列)
返回:一行多个字段示例:查询和 “张三” 同部门、同职位的员工
select emp.*
from emp
where (emp.dept_id, emp.job) = (
select emp.dept_id, emp.job
from emp
where emp.name = '张三'
);返回一行多列,需要用行构造器 (col1, col2, ...) 来匹配。
示例:查询与某员工薪资和职位都相同的其他员工
select name
from employees
where (salary, job_id) = (
select salary, job_id
from employees
where name = '张三'
);括号里的 (salary, job_id) 和子查询返回的 (salary, job_id) 一一对应进行比较。支持的操作符有 =、<>、<、> 等。
select * from emp33 where (salary,managerid) =(select salary,managerid from emp33 where name='张无忌');
等价于
select * from emp33 where managerid=(select managerid from emp33 where name='张无忌') and salary=(select salary from emp33 where name='张无忌');
4. 表子查询(多行多列)
子查询放在 from 后面,当作一张临时表使用,必须起别名。
示例:查询每个部门的平均薪资
sql
select temp.dept_id, temp.avg_sal
from (
select emp.dept_id, avg(emp.salary) as avg_sal
from emp
group by emp.dept_id
) as temp;三、子查询出现的 3 个位置(高频考点)
子查询不只能出现在 where 里,还可以出现在不同的位置:
| 位置 | 常见类型 | 说明 |
|---|---|---|
where / having | 标量、行、列 | 作为条件值 |
from | 表子查询 | 作为派生表,必须起别名 |
select 后 | 标量 | 作为查询字段值(关联子查询) |
1. 放在 where 后(最常用,标量、行、列)
select emp.name
from emp
where emp.dept_id = (
select dept.id
from dept
where dept.name = '财务部'
);2. 放在 from 后(当作表,表子查询)
select temp.name
from (
select emp.name
from emp
where emp.salary > 10000
) as temp;3. 放在 select 后(相关子查询,标量)
select
emp.name,
(
select dept.name
from dept
where dept.id = emp.dept_id
) as dept_name
from emp;四、子查询关键字详解(in / any / all / exists)
1. in
子查询返回多个值时用
select emp.*
from emp
where emp.dept_id in (
select dept.id
from dept
);2. any
满足子查询任意一个条件即可
select emp.*
from emp
where emp.salary > any (
select emp.salary
from emp
where emp.dept_id = 1
);3. all
必须满足子查询所有条件
select emp.*
from emp
where emp.salary > all (
select emp.salary
from emp
where emp.dept_id = 2
);4. exists
判断子查询是否有结果,有则为真
select emp.*
from emp
where exists (
select *
from dept
where dept.id = emp.dept_id
);五、子查询 vs 多表连接(对比)
- 子查询:逻辑清晰,适合分步查询
- 多表连接:效率更高,适合大数据量
示例(效果一样):
-- 子查询写法
select emp.name
from emp
where emp.dept_id = (
select dept.id
from dept
where dept.name = '研发部'
);
-- 多表连接写法
select emp.name
from emp
inner join dept
on emp.dept_id = dept.id
where dept.name = '研发部';六、子查询必须遵守的规则(考试必背)
- 子查询必须放在 括号内
- 标量子查询只能返回 一个值
- 列子查询返回 一列
- from 后的子查询 必须起别名
- 子查询先执行,主查询后执行
- 子查询中不能使用 order by(除非搭配 limit)
七、综合实战案例(最经典)
案例 1:查询工资最高的员工
select emp.*
from emp
where emp.salary = (
select max(emp.salary)
from emp
);案例 2:查询每个部门工资最高的员工
select emp.*
from emp
inner join (
select emp.dept_id, max(emp.salary) as max_sal
from emp
group by emp.dept_id
) as temp
on emp.dept_id = temp.dept_id
and emp.salary = temp.max_sal;案例 3:查询没有员工的部门
select dept.*
from dept
where dept.id not in (
select distinct emp.dept_id
from emp
where emp.dept_id is not null
);
理解子查询的关键在于:先看内层查询返回什么形状的数据,再根据形状选择合适的操作符和位置
总结
到此这篇关于mysql数据库中子查询、标量子查询、行子查询、列子查询及表子查询的文章就介绍到这了,更多相关mysql子查询内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论