码迷,mamicode.com
首页 > 数据库 > 详细

Oracle 查询(SELECT)语句(二)

时间:2019-12-29 17:02:27      阅读:101      评论:0      收藏:0      [点我收藏+]

标签:inter   rownum   行号   通过   round   实现   lan   最大值   roman   

?  简介

在前面的 Oracle 查询 SELECT 语句(一) 中介绍了 SELECT 常用的一些基本查询语法,接下来再来看 SELECT 更深入的一些查询功能和技巧,包括以下内容:

1.   All Any 运算符

2.   分页查询(rownum)

3.   集合操作符(UNIONUNION ALLINTERSECTMINUS)

 

1.   All Any 运算符

1)   All 运算符,表示满足给出列表中的所有值。通常用于以下场景:

1.   查出大于30号部门所有员工最高工资的员工姓名、工资

--使用ALL

SELECT ename, sal FROM emp WHERE sal > ALL(SELECT sal FROM emp WHERE deptno = 30);

--使用MAX

SELECT ename, sal FROM emp WHERE sal > (SELECT MAX(sal) FROM emp WHERE deptno = 30);

 

2)   Any 运算符,表示满足给出列表中的任意值。通常用于以下场景:

1.   查出大于30号部门任意员工的工资的员工姓名、工资

--使用ALL

SELECT ename, sal FROM emp WHERE sal > ANY(SELECT sal FROM emp WHERE deptno = 30);

--使用MIN

SELECT ename, sal FROM emp WHERE sal > (SELECT MIN(sal) FROM emp WHERE deptno = 30);

 

n  提示

通过以上示例,可以看到通常情况下,ALL ANY 都可以使用 MAX MIN 去取代,所有这两个运算符一般情况用的不多。分析如下:

比较运算符

All

Any

Max

Min

> 大于

取最大值

取最小值

取最大值

取最小值

< 小于

取最小值

取最小值

取最大值

取最小值

 

2.   分页查询(rownum)

Oracle 中分页,我们通常需要借助 ROWNUM 这个伪列来进行实现。这个列并不是真实存在的,当我们进行每一个 SELECT 查询时,Oracle 都会帮我们自动产生的这个序列号(rownum),用于标识行号。下面来看具体实现,比如我们需要取 emp 表中46行的记录:

1)   首先,我们来看一个奇怪的现象

SELECT * FROM emp WHERE rownum >= 4 AND rownum <= 6;

啪,一执行,呀,怎么没数据啊?这并不是我们写错了,要解释这个问题,我们先来看一个图,就明白其中原由了。


技术图片

由图可以看出,当我们取出第一条记录时,此时(rownum = 1) >= 3不成立,所以该记录会被排除;然后再取第二条,此时任然 rownum = 1,因为只有成功满足一条记录,rownum 才会加1,所以不满足又被排除掉了。这样依次类推,最终都不满足条件,所以全部都被排除掉了。所以,以下语句始终查不出数据:

SELECT * FROM emp WHERE rownum > 1;

 

然后,在看另外一边(就是接下来用的这种判断方式),首先取第一条(满足),第二条也满足,直到(rownum = 7) <= 6,所以会取出6条记录,此时 rownum 的值为1,2,3,4,5,6。好了,搞清楚原理后我们就来实现。

 

2)   根据对 rownum 的分析,便改为以下语句【推荐

SELECT rownum, t1.* FROM (

  SELECT rownum rnum, t1.* FROM emp t1 WHERE rownum <= 6

) t1 WHERE t1.rnum >= 4;

技术图片

这样,通过子查询,先取出前6行,再过滤掉前3行,就得到了我们需要的数据。注意:之前提过,每个 SELECT 都会产生一个 rownum 序列号,所有上面会可以输出两个 rownum 序列号,dual 也不例外

SELECT t1.*, rownum FROM dual t1;

技术图片

 

3)   除了使用以上语句,我们还可以这样写

SELECT rownum, t1.* FROM (

  SELECT rownum rnum, t1.* FROM emp t1

) t1 WHERE t1.rnum >= 4 AND rnum <= 6; --或使用 BETWEEN 子句

技术图片

同样,可以完成以上功能。但分析一下,这种方式视乎没有上面的方式效率高,因为,这里是先查出所有(先将 rownum 分配好)数据,再进行第二次 rownum 过滤。

 

4)   有时候,我们还需要通过排序后再分页,该怎么实现呢?

使用排序并分页,也需要注意以下问题。

首先,我们来看下排序的全部数据:

SELECT * FROM emp ORDER BY sal;

技术图片

按照上面的要求,我们应该是取出 empno(7521,7654,7934) 的员工,OK

 

不是说用第一种方式,效率很高么?那就来使用它实现,更改的后的 SQL

SELECT * FROM (

  SELECT rownum rnum, t1.* FROM emp t1 WHERE rownum <= 6 ORDER BY sal

) WHERE rnum >= 4;

技术图片

结果是不是又纳闷了?怎么76987566也出来,而且还不是按我们预想的排序的!

 

好,我们再做个假设,以上语法是不是先查询出结果后,再将结果集过滤和排序的呢?为了验证这个疑点,很简单我们做以下测试:

SELECT * FROM (

  SELECT * FROM (SELECT rownum rnum, t1.* FROM emp t1)

  WHERE rownum <= 6 ORDER BY sal

) WHERE rnum >= 4;

技术图片

结果与前面的推断是一样的,就是先查询出结果(产生的 rownum 是没有经过排序的),再排序,最后分页(过滤)。我们看一下未排序的原始数据:

SELECT rownum, t1.* FROM emp t1;

技术图片

所以,我们得出一个结论:当我们同时过滤 rownum 和排序时,是先按默认的排序生成 rownum 后,再进行排序和过滤的

 

5)   其实上面的排序和分页,并不是准确有效的。因为我们需要的是,rownum 的顺序是根据我们指定的排序产生的,这样再进行分页才是准确的。所以正确的排序和分页应该这样写:

SELECT * FROM (

  SELECT rownum rnum, t1.* FROM (SELECT * FROM emp ORDER BY sal) t1

) WHERE rnum BETWEEN 4 AND 6;

技术图片

执行步骤:先根据指定的字段排序;再产生 rownum 序列号;最后进行分页。

 

3.   集合操作符(UNIONUNION ALLINTERSECTMINUS)

Oracle 中对多个集合操作,主要使用 UNIONUNION ALLINTERSECTMINUS 这四个操作符来完成,解决取多个集合的并集交集差集

1)   UNIONUNION ALL

UNION UNION ALL 用于取两个结果集的并集,举例说明:

?  UNION,取出并集并去除重复行,例如:

SELECT * FROM emp WHERE empno <= 7500

UNION

SELECT * FROM emp WHERE empno < 7600;

技术图片

说明:

1.   两个查询的结果集中,都有两条记录小于7500UNION 在合并时进行去重了,所以相同的记录只会显示一行。

2.   UNION 逻辑上可以合并任意个结果集,所以只需要在后面接着写 UNION 即可。

 

?  UNION ALL,取出并集不会去除重复行,例如:

SELECT * FROM emp WHERE empno <= 7500

UNION ALL

SELECT * FROM emp WHERE empno < 7600;

技术图片

可见,两个结果集中具有两条相同的记录,UNION ALL 并没有去重。

 

2)   INTERSECT

INTERSECT 用于取两个结果集中相交的记录,即取得交集记录。还是以刚才的数据为例:

SELECT * FROM emp WHERE empno <= 7500

INTERSECT

SELECT * FROM emp WHERE empno < 7600;

技术图片

在两个查询的结果集中,存在两个完全相同的记录,这就是交集。

 

3)   MINUS

MINUS 中文意思是减去,表示第一个结果集减去第二个结果集,取出它们的差集。任然以刚才的数据为例:

SELECT * FROM emp WHERE empno <= 7600

MINUS

SELECT * FROM emp WHERE empno < 7500;

技术图片

取得两条记录,这两条记录是在第一个结果集中存在,在第二个结果集中不存在的记录,则为差集。

 

Oracle 查询(SELECT)语句(二)

标签:inter   rownum   行号   通过   round   实现   lan   最大值   roman   

原文地址:https://www.cnblogs.com/abeam/p/12115330.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!