oracle 子查询

12 篇文章 0 订阅

子查询 = 简单查询 + 限定查询 + 多表查询 + 统计查询的综合体;

在之前强调过多表查询不建议大家使用,因为性能很差,但是多表查询最有利的替代者就是子查询,所以子查询在实际的开发之中使用的相当的多;

所谓的子查询指的就是在一个查询之中嵌套了其他的若干查询,嵌套子查询之后的查询SQL语句如下:

复制代码
SELECT [DISTINCT] *|分组字段1 [别名] [,分组字段2 [别名] ,…] | 统计函数 ,(

      SELECT [DISTINCT] *|分组字段1 [别名] [,分组字段2 [别名] ,…] | 统计函数

      FROM 表名称 [别名], [表名称 [别名] ,…]

      [WHERE 条件(s)]

      [GROUP BY 分组字段1 [,分组字段2 ,…]]

      [HAVING 分组后的过滤条件(可以使用统计函数)]

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

FROM 表名称 [别名], [表名称 [别名] ,…] ,(

      SELECT [DISTINCT] *|分组字段1 [别名] [,分组字段2 [别名] ,…] | 统计函数

      FROM 表名称 [别名], [表名称 [别名] ,…]

      [WHERE 条件(s)]

      [GROUP BY 分组字段1 [,分组字段2 ,…]]

      [HAVING 分组后的过滤条件(可以使用统计函数)]

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

[WHERE 条件(s) (

      SELECT [DISTINCT] *|分组字段1 [别名] [,分组字段2 [别名] ,…] | 统计函数

      FROM 表名称 [别名], [表名称 [别名] ,…]

      [WHERE 条件(s)]

      [GROUP BY 分组字段1 [,分组字段2 ,…]]

      [HAVING 分组后的过滤条件(可以使用统计函数)]

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

[GROUP BY 分组字段1 [,分组字段2 ,…]]

[HAVING 分组后的过滤条件(可以使用统计函数)]

[ORDER BY 排序字段 ASC | DESC [,排序字段 ASC | DESC]];
复制代码

理论上子查询可以出现在查询语句的任意位置上,但是从个人而言,子查询出现在WHERE和FROM子句之中较多;

以下的使用特点为个人总结,不是官方声明的:

  • WHERE:子查询一般只返回单行列、多行单列、单行多列的数据;
  • FROM:子查询返回的一般是多行的数据,当作一张临时表出现。

范例:要求查询出工资比SMITH还要高的全部雇员信息

要想完成本程序,首先必须要知道SMITH的工资是多少:

SELECT sal FROM emp WHERE ename='SMITH';

由于此时返回的是单列的数据,所以这个子句查询可以在WHERE中出现。

SELECT * FROM emp
WHERE sal>(
SELECT sal
FROM emp
WHERE ename='SMITH');

范例:要求查询出高于公司平均工资的全部雇员信息

公司的平均工资应该使用AVG()函数求出。

SELECT AVG(sal) FROM emp;

此时数据的返回结果是单行单列的数据,在WHERE之中出现。

SELECT * FROM emp
WHERE sal>(
SELECT AVG(sal)
FROM emp);

以上所返回的是单行单列,但是在子查询之中,也可以返回单行多列的数据,只是这种子查询很少出现。

范例:子查询返回单行多列数据

SELECT * FROM emp
WHERE (job,sal)=(
SELECT job,sal
FROM emp
WHERE ename='ALLEN');

如果现在的子查询返回的是多行单列数据的话,这个时候就需要使用三种判断符判断了:IN、ANY、ALL;

1、 IN操作符:用于指定一个子查询的判断范围

这个操作符的使用实际上与之前讲解的IN是一样的,唯一不同的是,里面的范围由子查询指定了。

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

但是在使用IN的时候还要注意NOT IN的问题,如果使用NOT IN操作,在子查询之中,如果有一个内容是null,则不会查询出任何的结果。

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');
  • <ANY:比子查询中返回记录的最大的还要小;
SELECT * FROM emp
WHERE sal<ANY (
SELECT sal
FROM emp
WHERE job='MANAGER');

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

以上的所有子查询都是在WHERE子句中出现的,那么下面再来观察在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;

这个时候实际上是产生了笛卡尔积,一共产生了56条记录;

  • 新的解决方案:通过子查询完成,所有的统计查询只能在GROUP BY中出现,所以在子查询之中负责统计数据,而在外部的查询之中,负责将统计数据和dept表数据相统一。
复制代码
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(+);
复制代码

现在的程序中所操作的数据量:

  • 子查询中统计的记录是14条记录,最终统计的显示结果是3条记录;
  • dept表之中一共有4条记录;
  • 如果现在产生笛卡尔积的话只有12条记录,再加上雇员的14条记录,一共才26条记录;

通过如上的分析,可以发现,使用子查询的确要比使用多表查询更加节省性能,所以在开发之中子查询出现是最多的,而且在给出一个不成文的规定:大部分情况下,如果最终的查询结果之中需要出现SELECT子句,但是又不能直接使用统计函数的时候,就在子查询中统计信息,即:有复杂统计的地方大部分都需要子查询。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值