2、 ANY操作:一共分为三种形式:
◆ =ANY:功能与IN操作一样
查询 工资 与经理们的工资 相同的 所有雇员信息
SELECT * FROM emp
WHERE sal =ANY(
SELECT sal FROM emp WHERE job='MANAGER' ) ;
◆ >ANY:比 子查询返回的最小值 要大
查询工资比经理们之中的最低工资 要高的 所有雇员信息
SELECT * FROM emp
WHERE sal >ANY(
SELECT sal FROM emp WHERE job='MANAGER' ) ;
◆
查询 工资 比经理们之中的最高工资 要低的 所有雇员信息
SELECT * FROM emp
WHERE sal
SELECT sal FROM emp WHERE job='MANAGER' ) ;
3、 ALL操作:一共分为两种形式:
◆ >ALL:比 子查询返回的最大值 要大
查询 工资 比经理们之中的最高工资 要高的 所有雇员信息
SELECT * FROM emp
WHERE sal >ALL(
SELECT sal FROM emp WHERE job='MANAGER' ) ;
◆
查询 工资 比经理们之中的最低工资 要低的 所有雇员信息
SELECT * FROM emp
WHERE sal
SELECT sal FROM emp WHERE job='MANAGER' ) ;
在实际的开发之中,WHERE子句中,出现子查询的几率,是很高的。
【在HAVING子句里面使用子查询(次重点)】
如果子查询可以在HAVING子句里面出现,那么,只有一种情况,子查询返回的是单行单列数据,并且需要进行统计函数计算的时候。
范例:查询出高于公司平均工资的职位名称、职位人数、平均工资
◆ 找出公司的平均工资
SELECT AVG(sal) FROM emp ;
◆ 以上的查询返回的是单行单列,一般返回单行单列的数据,只会在WHERE或HAVING子句里面出现,但依据此题的要求,应该是在HAVING子句里面使用。
SELECT job, COUNT(empno), AVG(sal)
FROM emp
GROUP BY job
HAVING AVG(sal)>(
SELECT AVG(sal) FROM emp ) ;
在进行HAVING操作的过程之中,子查询返回的数据,不会过于的复杂。
【在SELECT子句里面使用子查询(了解)】
子查询可以出现在SELECT子句里面,只不过,大部分的开发者,如果不是万不得已的时候,绝对不会这么去做的。
范例:查询每个雇员的编号、姓名、职位、部门名称
◆ 如果,按照以前学习的多表查询,来做此题:
SELECT e.empno, e.ename, e.job, d.dname
FROM emp e, dept d
WHERE e.deptno=d.deptno ;
◆ 如果,在SELECT子句里面使用子查询,来做此题:
SELECT e.empno, e.ename, e.job,
( SELECT d.dname FROM dept d WHERE d.deptno=e.deptno )
FROM emp e ;
每当有一行emp的数据出现,那么,就要查询一次dept表,等于是你用户自己发出了一次的查询指令,
但是,却变为了“1+N”次查询,(如果emp表有100行数据,就会查询100次dept表),这种操作,一般不会有人去使用。
【在FROM子句里面使用子查询(重点)】
如果子查询返回的结构是多行多列的数据,那么,就相当于是一张临时表的形式,所以,可以直接在FROM子句里面使用,下面回顾一个原始的题目。
范例:查询出每个部门名称、位置、部门人数
◆ 之前,可以通过多表查询,而后,进行多字段分组实现:
SELECT d.dname, d.loc, COUNT(e.empno)
FROM emp e, dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.dname, d.loc ;
但是以上的功能,也可以使用子查询实现。
◆ 改善做法,利用子查询完成。
● 查询出部门的编号、名称、位置,此查询只需要dept一张表就够了。
SELECT d.deptno, d.dname, d.loc FROM dept d ;
● 统计出每个部门的编号、人数,此查询只需要emp一张表就够了。
SELECT deptno, COUNT(empno)
FROM emp GROUP BY deptno ;
● 通过以上的两个查询结果发现,可以在部门编号上,找到联系:
子查询 的列名称 不使用 别名 ( 会报错 )
SELECT d.dname, d.loc, temp.COUNT(empno)
FROM dept d, (
SELECT deptno, COUNT(empno)
FROM emp
GROUP BY deptno ) temp
WHERE d.deptno=temp.deptno(+) ;
子查询 的列名称 使用 别名
SELECT d.dname, d.loc, temp.count
FROM dept d, (
SELECT deptno, COUNT(empno) count
FROM emp
GROUP BY deptno ) temp
WHERE d.deptno=temp.deptno(+) ;
● 利用NVL( )函数,将null替换为0
SELECT d.dname, d.loc, NVL( temp.count , 0 )
FROM dept d, (
SELECT deptno, COUNT(empno) count
FROM emp
GROUP BY deptno ) temp
WHERE d.deptno=temp.deptno(+) ;
疑问? 发现多表查询也可以实现统计,子查询也能够实现统计,那么,哪种方式好呢?
为了可以更好的解释这个问题,假设将数据表中的数据扩大100倍,即:此时假设emp表有1400条记录,而dept表有400条记录。
◆ 使用多表查询及分组统计:
● emp表的1400条 × dept表的400条 = 560,000条记录
◆ 使用子查询:
● 子查询的数据量:只使用emp的1400条记录,最多返回400行统计结果。
(因为,子查询,是按照emp表中的部门编号deptno来进行分组统计的。
子查询,返回的是400个部门的部门编号,和每个部门所对应的雇员人数。
所以,子查询,返回的是400行记录。)
● 子查询的返回数据量400条 × dept表的400条 = 160,000条记录
● 两个操作,加在一起,最多只操作了:160,400条记录。
在实际的工作之中,子查询的主要目的是解决多表查询所带来的性能问题,所以,在开发之中,使用是最多的。
在编写代码的过程之中,我们很少直接去关注 多表查询,但是,我们都会关注 子查询,用 子查询 来改善 多表查询 所带来的 笛卡尔积 过多的问题。
在FROM子句出现子查询,一般还有一种情况:
“在整个查询语句之中,需要使用到统计函数,但是,又无法直接去使用统计函数的时候,可以先在FROM子句里面利用子查询实现统计”。
【总结】
复杂查询 = 简单查询 + 限定查询 + 多表查询 + 分组统计查询 + 子查询。
如果是子查询,首先考虑的一定是WHERE或FROM子句里面出现子查询的操作,像SELECT子句,几乎是可以忽略掉的,而HAVING子句出现子查询,只有在使用统计函数的时候,才会使用。
子查询,最大的作用是: 解决多表查询所带来的笛卡尔积影响的性能问题。