设为首页 收藏本站
查看: 693|回复: 0

[经验分享] Oracle TOPN分析及 rownum相关知识

[复制链接]

尚未签到

发表于 2016-7-25 09:23:58 | 显示全部楼层 |阅读模式
  ORACLE中经常会进行TOP N的查询,即列出按照一定排序的数据记录。这种查询操作分两种:
  
1.排序,列出所有记录或前N条记录
  
2.排序,列出指定区间的记录
  
  在ORACLE中是通过对表中的一个伪列 rownum进行操作的。也就是因为这一点,使得在ORACLE中进行TOP N的查询,尤其是指定区间的排序查询比较复杂和难以理解。
  
  现在我们先看看第一种,根据第一种的定义我们很容易写出以下语句:
  
  select 字段列表 from
  (select 字段列表 from 表名 order by 排序字段)
where rownum<=5
  
  以scott账户为例,要求:查出emp表中以工资降序的前5名员工的所有信息,查询语句如下:
  
  select * from
  (select * from emp order by sal desc)
where rownum<=5
  
  有的朋友可能笑了,这还用得着子查询?我写以下语句不也能搞定吗?
  
  a.select * from emp where rownum<=5 order by sal desc
  b.select * from emp order by sal desc  where rownum<=5
  
  以上两种查询语句都是不对的,先说b,大家要明白ORACLE的查询语句也有其固定语法的,如下:
  
  select 字段列表 from 表名 +where 子句  +group by 子句  +having 子句  +order by 子句,所以b不符合语法直接否定,这样的语句运行后会报语句没有正确结束的错误。
  
  而a查询语句执行后,返回的结果并不是我们预期的。这是因为虽然a查询语句虽然符合语法规则,但是逻辑上却不合理。它的逻辑意义是先取出前五条记录然后再排序,显然将我们所要做的TOP N分析的步骤搞反了。
  
  接下来我们继续看看第二种情况,有的朋友可能会从第一种情况中推理出以下语句:
  
  select 字段列表 from
  (select 字段列表 from 表名 order by 排序字段)
where rownum>=11 and rownum<=15
  
  毫无疑问,这句查询语句执行后不会有任何结果。要讲明白此查询语句的错误,我们就不得不把rownum拿出来研究研究了。
  
  首先大家要知道rownum是ORACLE在我们查询时自动生成的一个从1开始计数的伪列(就是一个虚假的列,看起来不存在,但是却实实在在存在,呵呵。。。比较难理解吧?要不我怎么说因为这点所以才造成ORACLE TOP N查询的困难呢?大家继续往下看,会慢慢理解的。我也是花了很多时间去理解的。)
  
  这个伪列的产生机理是这样:当我们进行查询操作时,数据库的记录一条一条拿出,并给词条记录自动生成伪列rownum,这里我再强调一下:rownum是从1开始计数的。
  
  那么让我们回头看看上边的查询语句为什么会什么都没有查到。当执行了查询操作后,数据库先拿出一条和查询条件比较。这里的查询条件有两个:rownum>=11 和rownum<=15。查询出的rownum是从1开始计数的,也就是拿出的记录rownum=1.它满足rownum<=15但是不满足rownum>=11。所以被无情的抛弃了。紧接着再拿出一条数据,当然这条数据还会走刚才那条数据的老路:自己的rownum的值被赋予了1,然后与rownum>=11 和rownum<=15的条件比较,结果当然还是被抛弃。这个时候大家也许就会恍然大悟了,如果数据库是这样运行的。那么就永远不会第一次取出rownum>=2的值了,更不用谈>=15了。所以以上的查询语句就不会有查询结果。
  
  要实现TOP N的查询第二种的实现我们不得不发挥我们的聪明才智了。于是有了以下的查询语句:
  
  select * from(select rownum myno,a.* from (select * from emp order by sal desc) a) b where myno>=5 and myno<=10;
  
  以上的语句由内到外划分可分为3部分:
  1.select * from emp order by sal desc
  这条查询语句是为其查询结果排序的,这个相当容易理解,再次不多讲解。
  
  2.select rownum myno,a.* from (select * from emp order by sal desc) a
  这条查询语句将第一条查询语句作为子查询,可以将第一条语句的查询结果作为一个临时表,并且别名为a。这张临时表中的记录与原来的emp表相同,只是全部排序过。
  本查询语句的查询结果就是 rownum myno   和 a.*.
  rownum myno 就是每条记录系统自动给赋予的rownum,读到这里有的朋友会问:为什么要给他起个别名呢?  答案是:不得不起,不然后面的业务没法开展。而且我们之所以能实现TOP N的查询第二种的实现最大的功臣就是这个别名了,继续往下看你就会明白。
  a.*就好理解了,指的就是a表的所有内容
  
  3.select * from(select rownum myno,a.* from (select * from emp order by sal desc) a)  b where myno>=5 and myno<=10;
  这条语句就是把第二条的查询结果作为子查询,作为一张临时表进行操作,别名为b.
b表中不仅有排序好的emp表的所有记录,此时它还多了一列实体列myno.通过对myno的操作进行查询就没有什么问题了。因为它是本来就存在的,并不是系统在查询时才临时生成的。你可以把myno理解为b表的固有列。如果在第三次查询时你用的是rowno而不是myno进行操作,那么你还会进入系统临时产生rowno的错误当中。
  
  总结一下其核心思想:就是将伪列rowno想办法实例为一个可操作的固有列,通过这个固有列来达到TOP N分析的第二种实现。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-248970-1-1.html 上篇帖子: 关于oracle的几个概念(二) 下篇帖子: Oracle 常用SQL技巧收藏(转)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表