Oracle SQL篇(三)Oracle ROWNUM 与TOP N分析

 

  
首先我们来看一下ROWNUM:
含义解释:
1、rownum是oracle为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推。这是一个伪列,可以用于限制查询返回的总行数。
2、rownum不能以任何基表的名称作为前缀。

对于ROWNUM来说,通常我们可以使用的比较符是<和<=,不能单独的使用=、>、>=等比较运算符,其实我们可以这样简单的 理解,oracle是找到第一条的记录添加序号1之后,才可以知道谁是第二条记录,然后添加序号2,以此类推。所以对于等于来说,是可以有例外的,就是 rownum=1。

我们来看几个简单的演示:
 
scott@DB01> create table demo as select demono,ename,sal,comm,deptno from demo;
Table created.
scott@DB01> select rownum,t.* from demo t;

    ROWNUM      demoNO ENAME             SAL       COMM     DEPTNO
---------- ---------- ---------- ---------- ---------- ----------
         1       7369 SMITH             800                    20
         2       7499 ALLEN            1600        300         30
         3       7521 WARD             1250        500         30
         4       7566 JONES            2975                    20
         5       7654 MARTIN           1250       1400         30
         6       7698 BLAKE            2850                    30
         7       7782 CLARK            2450                    10
         8       7788 SCOTT            3000                    20
         9       7839 KING             5000                    10
        10       7844 TURNER           1500          0         30
        11       7876 ADAMS            1100                    20
        12       7900 JAMES             950                    30
        13       7902 FORD             3000                    20
        14       7934 MILLER           1300                    10

14 rows selected.

scott@DB01> select rownum,demono,ename,sal from demo where rownum<=3;

    ROWNUM      demoNO ENAME             SAL
---------- ---------- ---------- ----------
         1       7369 SMITH             800
         2       7499 ALLEN            1600
         3       7521 WARD             1250

scott@DB01> select rownum,demono,ename,sal from demo where rownum<3;

    ROWNUM      demoNO ENAME             SAL
---------- ---------- ---------- ----------
         1       7369 SMITH             800
         2       7499 ALLEN            1600

scott@DB01> select rownum,demono,ename,sal from demo where rownum=1;

    ROWNUM      demoNO ENAME             SAL
---------- ---------- ---------- ----------
         1       7369 SMITH             800

scott@DB01> select rownum,demono,ename,sal from demo where rownum=3;

no rows selected

scott@DB01> select rownum,demono,ename,sal from demo where rownum>3;

no rows selected

如果我们想要查询结果集中的某一段范围的记录,比如5-10条的记录,该如何查询呢?很多开发人员把这样的需求称为分页
scott@DB01> select rownum,demono,ename,sal from demo where rownum between 5 and 10;
no rows selected

上面是一个错误的例子,我们来看正确的写法,这里我们使用到了集合运算符minus(减法运算)
scott@DB01> select rownum,demono,ename,sal from demo where rownum<=10
  2         minus
  3         select rownum,demono,ename,sal from demo where rownum<=4;

    ROWNUM      demoNO ENAME             SAL
---------- ---------- ---------- ----------
         5       7654 MARTIN           1250
         6       7698 BLAKE            2850
         7       7782 CLARK            2450
         8       7788 SCOTT            3000
         9       7839 KING             5000
        10       7844 TURNER           1500

6 rows selected.

如果我们有这样一个需求,找到员工demo表中,薪水最高的前三名,如何来实现呢?在sql server中有标准的top n分析语句,不过不要放到oracle里来使用,不同的数据库还是有区别的。当然了,也许你会认为这个问题有歧义,是前三个人呢?还是薪水排在最高3位的人?因为薪水有可能是相同的,在这里我们就找前三个人,看下面的语句:

scott@DB01> select rownum,demono,ename,sal
         2> from demo
         3> where rownum<=3
         4> order by sal desc;

    ROWNUM      demoNO ENAME             SAL
---------- ---------- ---------- ----------
         2       7499 ALLEN            1600
         3       7521 WARD             1250
         1       7369 SMITH             800

这个语句从表面上来看好像是正确的,从demo表里查询数据,排序,最后利用rownum返回前三个人,但是我们看语句的执行结果显然是不正确的。对于oracle的语句,我们在执行的时候遵循top-down的顺序,或者我们可以说,语句按照顺序来执行。

当然也有个别例外:
scott@DB01> select deptno,sum(sal) from demo
  2         group by deptno
  3         having sum(sal)>=10000;

    DEPTNO   SUM(SAL)
---------- ----------
        20      10875

scott@DB01> select deptno,sum(sal) from demo
  2         having sum(sal)>=10000
  3         group by deptno;

    DEPTNO   SUM(SAL)
---------- ----------
        20      10875

对于前面排名的语句当然是有问题的。当第2行语句执行后,拿到表中所有的数据,第3行语句紧接着执行,就把最前面的三条记录取出来了(rownum是对查询结果添加序号),这个时候,再做排序,当然拿到的就是对前面三条记录排序的结果,如上所示。

正确的思路应该是,先做排序,再做条件筛选,也就是4行子句要在3行之前运行,如何来实现呢?在这里oracle借助了子查询,用oracle的标准表述叫做内联视图(inline view),当然整个的sql就是oracle的top N分析语句的写法,我们来看例子:

scott@DB01>  select rownum rank,t.*
  2          from (select demono,ename,sal from demo order by sal desc) t
  3          where rownum<=3;

      RANK      demoNO ENAME             SAL
---------- ---------- ---------- ----------
         1       7839 KING             5000
         2       7788 SCOTT            3000
         3       7902 FORD             3000

在这里,oracle其实对内部子查询做了优化处理,我们通常认为,简单子查询是内层查询先执行,然后传递结果给外层查询,然后外层查询再执行。
但是对于这个例子,如果demo表数据量很大的话,那么内层排序需要花的时间就会非常多。而实际上呢,oracle会知道外层查询需要的记录数,如本例中是3,
oracle在对内层查询排序时,并不是对demo表中的14条记录做完全的排序,根据算法,他只要找到sal最高的3条就可以了,其余的11条记录是没必要排序的,这就大大的节省了语句的执行时间。

如果想要得到排序后的某段数据,我们可以通过嵌套的方法来实现:
scott@DB01> select t1.*        
  2         from   (select rownum rank,t.* from (select demono,ename,sal from demo order by sal desc) t) t1
  3         where rank>=3 and rank<=7;

      RANK      demoNO ENAME             SAL
---------- ---------- ---------- ----------
         3       7788 SCOTT            3000
         4       7566 JONES            2975
         5       7698 BLAKE            2850
         6       7782 CLARK            2450
         7       7499 ALLEN            1600
 

注:在前面两个例子中,我们使用到了oracle的top N分析,不过都是对整张表,或者整个结果集来说的。其实oracle 对于类似的操作,提供了一套函数,我们称之为分析函数,分析函数对于数据做统计和分析是非常有帮助的,我们在下面只是举一个简单的小例子,如果你感兴趣可以看看

scott@DB01> select * from demo;
     demoNO ENAME             SAL       COMM     DEPTNO
---------- ---------- ---------- ---------- ----------
      7369 SMITH             800                    20
      7499 ALLEN            1600        300         30
      7521 WARD             1250        500         30
      7566 JONES            2975                    20
      7654 MARTIN           1250       1400         30
      7698 BLAKE            2850                    30
      7782 CLARK            2450                    10
      7788 SCOTT            3000                    20
      7839 KING             5000                    10
      7844 TURNER           1500          0         30
      7876 ADAMS            1100                    20
      7900 JAMES             950                    30
      7902 FORD             3000                    20
      7934 MILLER           1300                    10

14 rows selected.

scott@DB01> break on deptno skip 1
scott@DB01> select *
  2  from (select deptno,
  3                ename,
  4                sal,
  5                dense_rank() over(partition by deptno order by sal desc) dr
  6        from demo
  7          )
  8  where dr<=3
  9  order by deptno;

    DEPTNO ENAME             SAL         DR
---------- ---------- ---------- ----------
        10 KING             5000          1
           CLARK            2450          2
           MILLER           1300          3

        20 SCOTT            3000          1
           FORD             3000          1
           JONES            2975          2
           ADAMS            1100          3

        30 BLAKE            2850          1
           ALLEN            1600          2
           TURNER           1500          3


10 rows selected.

scott@DB01> select * from (
  2                  select deptno,
  3                         ename,
  4                         sal,
  5                         row_number() over(partition by deptno order by sal desc) dr
  6                   from demo
  7                 )
  8  where dr<=3
  9  order by deptno;

    DEPTNO ENAME             SAL         DR
---------- ---------- ---------- ----------
        10 KING             5000          1
           CLARK            2450          2
           MILLER           1300          3

        20 SCOTT            3000          1
           FORD             3000          2
           JONES            2975          3

        30 BLAKE            2850          1
           ALLEN            1600          2
           TURNER           1500          3

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/260967.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ Primer 第10章 pair类型

//10.2.cpp //至少使用三种方法创建pair对象。 //编写三个版本的程序&#xff0c;分别采用不同的方法来创建pair对象 //方法1&#xff1a;在定义pair对象时提供初始化式来创建pair对象#include<iostream> #include<vector> #include<utility> #include<st…

计算机对口升学可以报考的学校,对口升学可以报考的学校都在这里,赶快来收藏吧...

对口升学指对口高考&#xff0c;在平常又叫对口单招&#xff0c;对口升学&#xff0c;是从中等职业学校毕业生招生&#xff0c;强调中等职业学校毕业生对口升高职的专业技能考试&#xff0c;以专业技能成绩为主要录取依据的招生办法。报名条件具有正式学籍的中等职业学校毕业生…

Visual Studio 常用快捷键 (二)

想不到上一篇 【Visual Studio 常用快捷键】 受这么多人的欢迎。看来大家对Visual Studio的用法非常感兴趣。 接下来我准备写一个 “Visual Studio使用技巧 ” 一个系列的博客。 希望对大家有所帮助 本篇继续介绍几个常用的快捷键 阅读目录 按两下Tab键回退到光标的上一次位置…

js 兼容event.target

function getEventTarget(e){ewindow.event||e;return e.srcElement||e.target; }转载于:https://www.cnblogs.com/manong13/archive/2012/02/23/2364443.html

企业邮箱收发信息服务器怎么设置,网易闪电邮企业邮箱收发设置教程(IMAP)...

网易闪电邮企业邮箱收发设置教程(IMAP)发表时间 2019-05-30人气 73(1)启动闪电邮后&#xff0c;点击“邮箱---新建邮箱账户”菜单&#xff0c;如下图&#xff1a;(2)输入“邮箱地址和密码”&#xff0c;点击下拉箭头继续设置&#xff0c;设置完成后点击下一步&#xff0c;如下图…

订餐系统之Excel批量导入

批量导入现在基本已经成为各类系统的标配了&#xff0c;当前&#xff0c;我们订餐系统也不例外&#xff0c;什么商家呀、商品呀、优惠码之类的&#xff0c;都少不了。毕竟嘛&#xff0c;对非开发人员来说&#xff0c;看到Excel肯定比看到很多管理系统还是要亲切很多的。这里&am…

需要忽略的一些信号

程序往往会因为收到一些信号导致退出&#xff0c;但很多时候并不是我们想要的&#xff0c;比如往一个已经关闭的socket连接发送数据就会受到SIGPIPE,此信号默认会退出程序&#xff0c;但其实大部分时候我们并不想这么做&#xff0c;所以需要忽略一些信号。常见的有 SIGPIPE SIG…

获取网页中选中的文字

获取页面中选中的文字 //获取页面中选中的文字 function getSelectedText(){if(window.getSelection){ //FFreturn window.getSelection().toString();}else{ //IEreturn document.selection.createRange().text;} }设置或获取输入框的选中文字 //设置文字选中 function setSe…

云服务器和独享虚拟主机的区别,独享虚拟主机和云服务器的几大区别

独享虚拟主机和云服务器的几大区别发布时间&#xff1a;2020-10-15 19:05:51来源&#xff1a;亿速云阅读&#xff1a;99作者&#xff1a;Leah栏目&#xff1a;云计算今天就跟大家聊聊有关独享虚拟主机和云服务器的几大区别&#xff0c;可能很多人都不太了解&#xff0c;为了让大…

oracle数据库之数据导入问题

2019独角兽企业重金招聘Python工程师标准>>> 在oracle数据库中建立好数据库以后&#xff0c;需要使用PLSQL进行用户创建&#xff0c;打开PLSQL&#xff0c;使用时需要使用最高权限进入PLSQL。如下图&#xff1a; 不需要使用用户名和密码&#xff0c;进入数据库操作。…

转向ARC的说明

转自hherima的博客原文&#xff1a;Transitioning to ARC Release Notes&#xff08;苹果官方文档&#xff09; ARC是一个编译器特征&#xff0c;它提供了对OC对象自动管理内存。ARC让开发者专注于感兴趣的代码和对象的关系&#xff0c;而不用考虑对象的retain和release。 概要…

ubuntu11.10 samba服务器配置

安装samba可以实现linux下文件和window共享&#xff0c;这样window下就可以操作linux的文件了。 1、关闭LINUX防火墙 sudo ufw disable 注&#xff1a;ufw是linux下的防火墙操作命令&#xff0c;相关的操作可以查看命令帮助 2、先卸载samba-common sudo ap…

win服务器创建文件夹命令,Win10系统如利用命令提示符或WSL创建任意大小空白文件...

要测试网盘或服务器的上传&#xff0c;下载速度&#xff0c;需要指定大小的文件用来测试。创建的空白文件虽然没有任何内容&#xff0c;但是有大小&#xff0c;可以用来测试实际传输速度、覆盖已删除数据等用途。这篇文章是本站教大家在Win10中用命令或WSL创建任意大小空白文件…

计算UILabel带行间距的行高

为什么80%的码农都做不了架构师&#xff1f;>>> //设置lab的行间距 NSMutableAttributedString *attributedString [[NSMutableAttributedString alloc] initWithString:_doubletStr]; NSMutableParagraphStyle *paragraphStyle [[NSMutableParagraphStyle alloc…

FORM级别和数据库级别的Trace

&#xfeff;&#xfeff;metalink上的文章较全的&#xff0c;中文的可参考我的博客EBS开发技术之trace http://blog.csdn.net/cai_xingyun/article/details/17250971 This document provides instructions on how to create and retrieve Forms and Database level SQL trace…

关于farpoint公司的控件:SPREAD for .NET Windows Forms Ed.的一些简单方法.

View Code using System;using FarPoint.Win.Spread ;using System.Drawing;using System.Windows.Forms;namespace DFO010{/// <summary>/// Fpspread的相关函数.2006/4/12 制作:Chouka/// </summary> public class Classspd {public Classspd() { }/// <su…

永远的beyond!(4 days left to get back touch)

永远的beyond!转载于:https://www.cnblogs.com/LaoLuo/archive/2012/03/05/2380954.html

串行总线协议笔记

I2C --INTER-IC串行总线的缩写&#xff0c;是PHILIPS公司推出的芯片间串行传输总线。它以1根串行数据线&#xff08;SDA&#xff09;和1根串行时钟线&#xff08;SCL&#xff09;实 现了双工的同步数据传输。具有接口线少&#xff0c;控制方式简化&#xff0c;器件封装形式小&a…

ibm服务器和微软,微软与IBM不得不说的事情

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼在Windows 3.x 开 始 为 世 人 接 受 之 初&#xff0c; 个 人 电 脑 的 操 作 系 统 中 唯 一 可 以 与Windows 操 作 系 统 分 庭 抗 礼 的 就 是OS/2。 这 套 原 先 是 微 软 与IBM 合 作 生 产 的 操 作 系 统&#xff0c; 由 …

[置顶] 程序员编程生产力相差10倍意味着什么?

在软件工程研究中&#xff0c;被验证得最多的结论就是对于同等经验的两个不同程序员&#xff0c;在效率和质量上可能会有10倍的差距。研究人员还发现&#xff0c;这种差距也适用于团队级别上&#xff0c;也就是说在同一行业内的不同的团队也是如此。 软件开发中的个人效率的变化…