一、子查询概述
定义:
- 出现在其他语句中的select语句,称为子查询或内查询
- 外部的查询语句,称为主查询或外查询
为什么要学习子查询?
例:查询工资比张三高的员工信息
-- 查询工资比张三高的员工信息
-- 1.查询张三的工资
select sal from emp where ename='张三';
-- 2. 比3000元高的员工信息
select * from emp where sal >3000;
张三的工资是3000元,这3000元是作为条件,在第二步当作为条件使用。
这里需要两个步骤,而使用子查询之后,使用一步就可以解决该问题。
因此子查询要解决的问题是:问题不能一步求解的问题。
二、子查询的使用
子查询的语法:select语句的嵌套。
SELECT select_list
FROM table
WHERE expr operator (
SELECT select_list
FROM table
)
使用子查询解决:查询工资比张三高的员工信息
select *
from emp
where sal > (
select sal
from emp
where ename='张三'
);
子查询注意的10个问题:
【1】子查询语法中的小括号
select e.*
from sal > (select min(sal) from emp where deptno=30)
【2】子查询的书写风格
【3】可以使用子查询的位置:where,select,having,from
【4】不可以使用子查询的位置:group by
【5】强调:from 后面的子查询语句
【6】子查询和主查询可以不是同一张表
只要子查询的结果在主查询当中可以使用就行了。
例子:查询部门名称是行政部的员工信息
--方法一:使用子查询
-- 这里子查询是使用表dept,而外层则是使用emp表
select *
from emp
where deptno=(select deptno
from dept
where dname='行政部')
--方法二:使用多表查询
-- 从理论上面来讲,使用多表查询好于子查询
select e.*
from emp e,dept d
where e.deptno=d.deptno and d.dname='行政部'
【7】一般不在子查询中,使用排序(因为没有意义);
但是在Top-N分析问题中,必须对子查询排序
Top-N分析问题:指的是按照某个规律排序以后,取出前几条记录。
【8】一般先执行子查询,再执行主查询,但相关子查询例外
【9】单行子查询只能使用单行操作符;多行子查询只能使用多行操作符
【10】注意子查询中是null值问题:子查询分为单行子查询和多行子查询
1、单行子查询
- 单行子查询:子查询只返回一条记录
单行操作符:= , > , >= ,< <= ,<>
单行子查询事例:
select *
from emp
where job=(select job from emp where empno=7655) and
sal>(select sal from emp where empno=6088);
-- 查询工资最低的员工的信息
select *
from emp
where sal=(select min(sal) from emp) -- 在子查询当中也可以使用分组函数
-- 查询最低工资大于20号部门最低工资的部门号和部门的最低工资:
--先得到每个部门的最低工资,在查出20号部门的最低工资,然后筛选
select deptno ,min(sal)
from emp
group by deptno
having min(sal) > (select min(sal)
from emp
where deptno=20)
2、多行子查询
- 多行子查询:子查询返回多条记录
多行操作符:
【1】in
【1】IN:等于列表中的任何一个
例子: 查询部门名称是销售部或者财务部的员工信息
方法一:子查询+in
-- 方法一:子查询+in
select *
from emp
where deptno in (select deptno
from dept
where dname='销售部' or dname='财务部')
方法二:使用多表查询
select e.* -- 查询员工的所有信息
from emp e,dept d
where e.deptno=d.deptno and (d.dname='销售部' or d.dname='财务部')
【2】any
【2】ANY:和子查询返回的任意一个值比较
ANY在使用中有如下三种使用形式:
-
=ANY
:表示与子查询中的每个元素进行比较,功能与IN类似(然而<>ANY不等价于NOT IN) -
>ANY
:比子查询中返回结果的最小的要大(还包含了>=ANY) -
<ANY
:比子查询中返回结果的最大的要小(还包含了<=ANY)
例子:查询工资比30号部门任意一个员工高的员工信息
方法一:
select e.*
from sal > any (select sal from emp where deptno=30)
方法二:
-- 分析:大于任意一个,只要大于最小的那个就行了
select e.*
from sal > (select min(sal) from emp where deptno=30)
【3】all
ALL操作符有以下三种用法:
<>ALL
:等价于NOT IN(但是=ALL并不等价于IN)>ALL
:比子查询中最大的值还要大(还包含了>=ALL)<ALL
:比子查询中最小的值还要小(还包含了<=ALL)
【3】ALL:和子查询返回的所有值比较
例子:查询工资比30号部门所有员工高的员工信息
方法一:使用子查询的any
select e.*
from sal> any ( select sal from emp where deptno=30)
方法二:大于子查询的最大值即可
select e.*
from sal> ( select max(sal) from emp where deptno=30)
- 在where后面使用子查询
select *
from emp
where sal>(
select sal
from emp
where ename='张三'
);
- 在select后面使用子查询
在select后面使用子查询必须是单行子查询
-- 错误写法,因为此时子查询是多行记录
select empno,ename,sal,(select job from emp )
--正确写法:
select empno,ename,sal,(select job from emp where empno=7893) from emp;
- 在having后面使用子查询
select deptno,avg(sal)
from emp
group by deptno
having avg(sal) > (select max(sal)
from emp
where deptno=30);
- 在from后面使用子查询
select *
from ( select empno,ename,sal from emp )
--例一:查询员工信息:员工号,姓名,月薪
select *
from (select empno,ename,sal from emp)
--例二:查询员工信息:员工号,姓名,月薪,年薪
select *
from (select empno,ename,sal,sal*12 as annsal from emp)
3、子查询中的空值问题
【1】单行子查询当中的空值问题
必须使用in或者
由于条件为假,因此子查询不返回任何值。
【2】多行子查询当中的空值问题
例子:查询不是老板的员工
在emp表当中,有一列MGR,代表该员工的老板的编号
为什么not in得不到正确的结果呢:
因为not in 等价于 不等于集合的所有元素
a not in(10,20,null)
-- 等价于
a != 10 and a!=20 and a!=null
-- 而a!=null 这个条件永远为假 ,因为判断一个值等不等于空值,
--不能使用等于或者不等于,因为永远是不等于。
因此多行子查询中如果存在空值,就不能使用not in 。但是如果子查询的结果包含空值,是可以使用in,因为这里in等同于any,any是取集合当中的一个值,不用和集合中的所有值进行比较。
在多行子查询当中,且包含空值,使用not in 的正确写法如下:
select *
from emp
where empno not in(
select mgr
from emp
where mgr is not null)