zoukankan      html  css  js  c++  java
  • Oracle Top N 和 Oracle中的limit问题解决方案

    oracle top N

    1.在ORACLE中实现SELECT TOP N

       由于ORACLE不支持SELECT TOP语句,所以在ORACLE中经常是用ORDER BY跟ROWNUM的组合来实现SELECT TOP N的查询。

    简单地说,实现方法如下所示:

          SELECT 列名1...列名n FROM

            (SELECT 列名1...列名n FROM 表名 ORDER BY 列名1...列名n)

           WHERE ROWNUM <= N(抽出记录数)

          ORDER BY ROWNUM ASC

       下面举个例子简单说明一下。

    顾客表customer(id,name)有如下数据:

          ID NAME

           01 first

           02 Second

           03 third

           04 forth

           05 fifth

           06 sixth

           07 seventh

           08 eighth

           09 ninth

           10 tenth

           11 last

       则按NAME的字母顺抽出前三个顾客的SQL语句如下所示:

          SELECT * FROM

            (SELECT * FROM CUSTOMER ORDER BY NAME)

           WHERE ROWNUM <= 3

           ORDER BY ROWNUM ASC

       输出结果为:

          ID NAME

           08 eighth

           05 fifth

           01 first

    2.在TOP N纪录中抽出第M(M <= N)条记录

    在得到了TOP N的数据之后,为了抽出这N条记录中的第M条记录,我们可以考虑从ROWNUM着手。我们知道,ROWNUM是记录表中数据编号的一个隐藏子段,所以可以在得到TOP N条记录的时候同时抽出记录的ROWNUM,然后再从这N条记录中抽取记录编号为M的记录,即使我们希望得到的结果。

    从上面的分析可以很容易得到下面的SQL语句。

          SELECT 列名1...列名n FROM

             (

             SELECT ROWNUM RECNO, 列名1...列名nFROM

               (SELECT 列名1...列名n FROM 表名 ORDER BY 列名1...列名n)

             WHERE ROWNUM <= N(抽出记录数)

           ORDER BY ROWNUM ASC

             )

           WHERE RECNO = M(M <= N)

    同样以上表的数据为基础,那么得到以NAME的字母顺排序的第二个顾客的信息的SQL语句应该这样写:

           SELECT ID, NAME FROM

             (

              SELECT ROWNUM RECNO, ID, NAME FROM

                (SELECT * FROM CUSTOMER ORDER BY NAME)

                 WHERE ROWNUM <= 3

                 ORDER BY ROWNUM ASC )

               WHERE RECNO = 2

         结果则为:

           ID NAME

            05 fifth

    3.抽出按某种方式排序的记录集中的第N条记录

       在2的说明中,当M = N的时候,即为我们的标题讲的结果。实际上,2的做法在里面N>M的部分的数据是基本上不会用到的,我们仅仅是为了说明方便而采用。

       如上所述,则SQL语句应为:

           SELECT 列名1...列名n FROM

             (

              SELECT ROWNUM RECNO, 列名1...列名nFROM

                (SELECT 列名1...列名n FROM 表名 ORDER BY 列名1...列名n)

                 WHERE ROWNUM <= N(抽出记录数)

              ORDER BY ROWNUM ASC

             )

             WHERE RECNO = N

         那么,2中的例子的SQL语句则为:

            SELECT ID, NAME FROM

              (

               SELECT ROWNUM RECNO, ID, NAME FROM

                 (SELECT * FROM CUSTOMER ORDER BY NAME)

               WHERE ROWNUM <= 2

               ORDER BY ROWNUM ASC

              )

              WHERE RECNO = 2

         结果为:

           ID NAME

            05 fifth

    4.抽出按某种方式排序的记录集中的第M条记录开始的X条记录

           3里所讲得仅仅是抽取一条记录的情况,当我们需要抽取多条记录的时候,此时在2中的N的取值应该是在N >= (M + X - 1)这个范围内,当让最经济的取值就是取等好的时候了的时候了。当然最后的抽取条件也不是RECNO = N了,应该是RECNO BETWEEN M AND (M + X - 1)了,所以随之而来的SQL语句则为:

           SELECT 列名1...列名n FROM

            (

             SELECT ROWNUM RECNO, 列名1...列名nFROM

              (

              SELECT 列名1...列名n FROM 表名 ORDER BY 列名1...列名n)

              WHERE ROWNUM <= N (N >= (M + X - 1))

            ORDER BY ROWNUM ASC

              )

             WHERE RECNO BETWEEN M AND (M + X - 1)

        同样以上面的数据为例,则抽取NAME的字母顺的第2条记录开始的3条记录的SQL语句为:

           SELECT ID, NAME FROM

             (

              SELECT ROWNUM RECNO, ID, NAME FROM

                (SELECT * FROM CUSTOMER ORDER BY NAME)

              WHERE ROWNUM <= (2 + 3 - 1)

              ORDER BY ROWNUM ASC

             )

             WHERE RECNO BETWEEN 2 AND (2 + 3 - 1)

         结果如下:

           ID NAME

            05 fifth

            01 first

            04 forth

        以此为基础,再扩展的话,做成存储过程,将开始记录数以及抽取记录数为参数,就可以轻松实现分页抽取数据。

    Oracle中的limit问题解决方案
    2009-05-12 17:19

    从mysql到oracle迁移一个程序,遇到了sql语句中的limit问题。
    查遍网络,所提供的方法都极其麻烦,不利于通用。
    以下是我的解决方案,可以与limit媲美。

    比如从一个mobileuser 用户表中查询2到6条记录,按照第一次使用时间排序。

    mysql语句为:

    SELECT userid,password,firstusetime from mobileuser ORDER BY firstusetime DESC limit 2,6;

    oracle语句为:

    SELECT * FROM ( SELECT userid,password,firstusetime, RANK() OVER (ORDER BY firstusetime DESC ) RN   FROM mobileuser ) WHERE RN between 2 and 6;


    rank() over 函数代表排行依据,整个sql语句就是从根据“ORDER BY firstusetime DESC”这个标准,找到排行2到6位的数据。

    但是存在一个问题,根据排行依据,有些数据是并列的,这样返回的数据条数就会多于我们期望的。这时我们加一个rownum限制就行了。

    SELECT * FROM ( SELECT userid,password,firstusetime, RANK() OVER (ORDER BY firstusetime DESC ) RN   FROM mobileuser ) WHERE RN between 2 and 6 and rownum<=5;

  • 相关阅读:
    BadUSB 利用
    java 将函数作为参数传递
    odoo12 修行提升篇之 常用的高阶函数 (二)
    odoo12 修行提升篇之 异步定时任务 (一)
    odoo12 修行基础篇之 利用kanban做分析 点击跳转分析模型列表 (九)
    odoo12 修行基础篇之 kanban (八)
    odoo12 修行基础篇之 记录批处理 (七)
    odoo12 修行基础篇之 列表的筛选和分组 (六)
    odoo12 修行基础篇之 添加记录编码 (五)
    odoo12 修行基础篇之 添加工作流和操作记录 (四)
  • 原文地址:https://www.cnblogs.com/cuker919/p/4878664.html
Copyright © 2011-2022 走看看