天天看点

Oracle数据库——子查询-07

子查询(核心,难点)

子查询没有任何固定的语法,因为子查询是一个综合体,将之前所学习过的限定查询,多表查询,分组统计

查询融合在一起形成新的查询方式,而且在开发之中子查询的使用是最多的,一定会用的

如果非要给子查询的语法,那么可以参考如下形式:

SELECT [DISTINCT] * | 列名称 [别名],...|统计函数|分组字段  

,(SELECT [DISTINCT] * | 列名称 [别名],...|统计函数|分组字段  

FROM 表名称 [别名]    

WHERE 限定条件(s)

[GROUP BY 分组字段,分组字段,..]    ==<字段数据有重复

[HAVING 分组后过滤]

[ORDER BY 排序字段[ASC|DESC],排序字段[ASC|DESC],...];  )

FROM 表名称 [别名]    

WHERE 限定条件(s)

[GROUP BY 分组字段,分组字段,..]    ==<字段数据有重复

SELECT [DISTINCT] * | 列名称 [别名],...|统计函数|分组字段  

FROM 表名称 [别名]    

WHERE 限定条件(s),(SELECT [DISTINCT] * | 列名称 [别名],...|统计函数|分组字段  

FROM 表名称 [别名]    

WHERE 限定条件(s)

[GROUP BY 分组字段,分组字段,..]    ==<字段数据有重复

[HAVING 分组后过滤]

[ORDER BY 排序字段[ASC|DESC],排序字段[ASC|DESC],...];  )

[GROUP BY 分组字段,分组字段,..]    ==<字段数据有重复

[HAVING 分组后过滤]

[ORDER BY 排序字段[ASC|DESC],排序字段[ASC|DESC],...];  

[HAVING 分组后过滤]

[ORDER BY 排序字段[ASC|DESC],排序字段[ASC|DESC],...];  

理论上子查询可以出现在一条SQL语句的任意位置之中,但是必须使用“()”声明,而一般在开发之中以下

几个子句出现子查询是比较常见

  • WHERE子句:子查询一般返回单行单列,单行多列,多行单列数据:
  • HAVING子句:子查询返回单行单列而且要使用统计函数;
  • FROM子句:子查询返回多行多列数据
  • 在WHERE子句之中使用子查询

WHERE子句之中出现的在查询表示子查询返回的单行单列,多行单列,单行多列三种数据

1.子查询返回单行单列

范例:查出公司工资最低的雇员信息

第一步:找到公司的最低工资,依靠MIN()函数统计,不需要GROUP BY

SELECT MIN(sal) FROM emp;

第二步:以上的查询返回有单行单列的结构

SELECT * FROM emp

WHERE sal=(SELECT MIN(sal) FROM emp);

范例:查出公司雇佣最早的雇员信息

第一步:找出最早的雇员日期是多少

SELECT MIN(hiredate) FROM emp;

第二步:以上的查询返回有单行单列的数据,根据需求肯定在WHERE之中使用

SELECT * FROM emp

WHERE hiredate=(SELECT MIN(hiredate) FROM emp);

2.子查询返回单行多列(了解)

范例:查询出与SCOTT工作相同,工资相同的雇员信息

第一步,找到SCOTT的工作和工资

SELECT job,sal FROM emp WHERE ename='SCOTT';

第二步:以上的结果返回的单行二列的数据

SELECT * FROM emp

WHERE (job,sal)=(

SELECT job,sal FROM emp WHERE ename='SCOTT') AND ename<>'SCOTT';

范例:查询公司雇佣日期最早,工资最低的雇员

第一步:统计出公司的最早雇佣日期和最低工资

SELECT MIN(hiredate),MIN(sal) FROM emp;

第二步:以上查询返回单行多列,在WHERE中使用

SELECT * FROM emp

WHERE (hiredate,sal)=(SELECT MIN(hiredate),MIN(sal) FROM emp);

3.子查询返回多行单列数据

在之前使用过IN查询,IN查询是规定了一个范围,那么如果子查询返回的是多行单列数据,实际上也是

一个范围,例如:

范例:查询所有经理的工资

SELECT sal  FROM emp WHERE job='MANAGER';

这个时候是多行单列数据,所以它就是一个数据的参考范围,而对于数据库的参考范围可以使用三种

符号进行判断:IN,ANY,ALL

(一)IN操作

此操作与之前讲解过的IN使用形式类似

SELECT sal  FROM emp WHERE job='MANAGER';

SELECT * FROM emp

WHERE sal IN (SELECT sal  FROM emp WHERE job='MANAGER');

但是需要注意的是,如果此时使用的是NOT IN,子查询如果有null值返回,则不会有任何的查询结果返回

SELECT * FROM emp

WHERE comm NOT IN(SELECT comm FROM emp);

(二)ANY操作

对于ANY操作表示的也是子查询中的每一个结果进行比较,而ANY有三种使用方式

>ANY:比子查询之中返回最小的值要大

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');

=ANY:与IN判断的功能完全相同

SELECT * FROM emp

WHERE sal=ANY (SELECT sal  FROM emp WHERE job='MANAGER');

(三)ALL操作

对于ALL也有两种使用方式

>ALL:比子查询之中返回最大的值要大

SELECT * FROM emp

WHERE sal>ALL(SELECT sal  FROM emp WHERE job='MANAGER');

<ALL:比子查询之中返回最小的值要小

SELECT * FROM emp

WHERE sal<ALL(SELECT sal  FROM emp WHERE job='MANAGER');

至于工作之中使用那个,请根据具体的业务需求来决定

在HAVING中使用子查询

HAVING一定是在GROUP BY之后使用的,表示对分组后的数据进行再次的过滤。如果子查询出现在HAVING

之中,则表示要使用统计函数,而此时的子查询肯定返回的是单行单列数据。

范例:统计出每个部门的编号,平均工资,并且要求这些部门的平均工资高于公司平均工资

第一步:统计出公司的平均工资

SELECT AVG(sal)FROM emp;

第二步:根据需求需要统计查询

SELECT deptno,AVG(sal)

FROM emp

GROUP BY deptno

HAVING AVG(sal)>(SELECT AVG(sal)FROM emp);

如果没有统计,那么就没有HAVING

在SELECT子句中使用子查询(没用)

在SELECT之中使用子查询的情况很少见

范例:查询雇佣编号是7369的姓名,职位,工资,部门名称

SELECT ename,job,sal,

(SELECT d.dname FROM dept d WHERE d.deptno=e.deptno)

FROM emp e

WHERE empno=7369;

这种查询非常可怕,会带来”1+N“此查询问题,例如:现在需求变更,查询出每个雇员的编号,姓名,

职位,部门名称,如果采用以上的代码怎么改昵?

SELECT e.empno,e.ename,e.job,e.sal,

(SELECT d.dname FROM dept d WHERE d.deptno=e.deptno)

FROM emp e;

这个时候查询出全部的雇员需要执行1此查询,而且每一次操作之中,SELECT子句又会查询dept表

,如果emp返回有20行记录,那么就要查询20次的dept表

在FROM子句中使用子查询(核心)

FROM子句主要的功能来确定数据源的,所以如果在FROM子句里面出现子查询,子查询只会返回一种结构:

多行多列(临时表)。

范例:统计出每个部门的编号,名称,位置,部门人数,平均工资

实现方式一:采用多表关联查询统计

SELECT d.deptno,d.dname,d.loc,COUNT(e.empno),AVG(e.sal)

FROM emp e,dept d

WHERE e.deptno(+)=d.deptno

GROUP BY d.deptno,d.dname,d.loc;

实现方式二:利用子查询完成

第一步:查询出每个部门的编号,部门人数,平均工资。只需要emp一张表就可以解决

SELECT deptno,COUNT(empno),AVG(sal)

FROM emp

GROUP BY deptno;

第二步:以上的查询返回的是多行多列数据,这属于一种表的结构,那么可以直接在FROM之后编写,但是

为了方便操作可以为它起一个别名

SELECT d.deptno,d.dname,d.loc,temp.count,temp.avg

FROM dept d,(SELECT deptno dno,COUNT(empno) count,AVG(sal) avg

         FROM emp

             GROUP BY deptno) temp

WHERE d.deptno=temp.dno(+);

讨论:两种查询操作使用哪一种更好?

为了更好的分析出使用哪种方式好操作,将表中的数据各自扩大100倍,即:emp表1400条记录,而dept表

400条记录,于是进行对比

使用多字段分组数据量:emp表的1400*dept表的400=560000条记录

使用子查询统计

子查询数据量:emp表的1400,最多返回400行记录

子查询与dept表关联:子查询的最多400行*dept表的400行=160000行记录

整体记录:161400条记录

所以通过以上的分析一定要清楚,在日后的开发之中,尽量要回避多表查询,而使用子查询性能会更好

在FROM之中出现子查询还有另外一种功能,指的是整个查询已经无法继续使用统计函数,但是又必须统计

信息的情况下,也可以考虑FROM之后的子查询。

继续阅读