Oracle数据库中实现分页

ops/2024/10/21 3:47:28/

在Oracle数据库中实现分页通常有以下几种方法,每种方法都有其适用场景和优缺点。

1. 使用ROWNUM

ROWNUM是Oracle为结果集的每一行分配的一个唯一的数字,这个数字表示行被检索出来的顺序。但是,需要注意的是,ROWNUM是在结果集产生之后才被赋予的,并且只能在一个查询中直接引用一次。因此,使用ROWNUM进行分页时,常常需要嵌套查询。

示例

假设我们有一个名为employees的表,我们想获取第n页的数据,每页显示m条记录。

SELECT * FROM (SELECT a.*, ROWNUM rnum FROM (SELECT * FROM employees ORDER BY employee_id) aWHERE ROWNUM <= (n-1)*m + m
)
WHERE rnum > (n-1)*m;

这里,(n-1)*m + m表示从第一行到第n页最后一行的ROWNUM范围,而外部查询则用于去除掉不需要的前(n-1)*m行记录。

2. 使用FETCH FIRST ... ROWS ONLYOFFSET ... ROWS(Oracle 12c及以后版本)

从Oracle 12c开始,Oracle引入了FETCH FIRST ... ROWS ONLYOFFSET ... ROWS子句来简化分页查询。这种方法比使用ROWNUM更加直观和易于理解。

示例

SELECT * FROM employees
ORDER BY employee_id
OFFSET (n-1)*m ROWS FETCH NEXT m ROWS ONLY;

这里,OFFSET (n-1)*m ROWS表示跳过前(n-1)*m行记录,FETCH NEXT m ROWS ONLY表示接着取m行记录。

3. 使用第三方工具或框架

在实际开发中,我们往往不会直接写SQL进行分页,而是使用ORM框架(如Hibernate、MyBatis等)或数据库访问工具(如Spring Data JPA)等提供的分页功能。这些工具或框架通常会封装好分页的逻辑,让我们只需要提供分页的参数(如页码和每页显示的记录数)即可。

4. 使用存储过程的分页

4.1. 首先创建一个包package_cursor 并定义一个类型 p_cursor 是一个游标
create or replace package package_hr_emp
as
type type_cursor is ref cursor;
type type_record is record
(   empno  EMPLOYEES.EMPLOYEE_ID%TYPE,empname  EMPLOYEES.FIRST_NAME%TYPE,lastname EMPLOYEES.LAST_NAME%TYPE,email EMPLOYEES.EMAIL%TYPE,phone_number EMPLOYEES.PHONE_NUMBER%TYPE,hire_date EMPLOYEES.HIRE_DATE%TYPE,job_id EMPLOYEES.JOB_ID%TYPE,salary EMPLOYEES.SALARY%TYPE,                                            comm_pct EMPLOYEES.COMMISSION_PCT%TYPE,manager_id EMPLOYEES.MANAGER_ID%TYPE,dept_id EMPLOYEES.DEPARTMENT_ID%TYPE,Rn number	
);end;
/
4.2. 创建分页存储过程
CREATE OR REPLACE PROCEDURE sp_GetPageSizeList_Plsql
(p_tablename IN  VARCHAR2,--分页的表p_Rows IN  NUMBER,--每页显示的条数p_Current IN  NUMBER,--当前是第几页p_RowCount OUT NUMBER,--总结果行数p_PageSum OUT NUMBER,--总页数p_CursorList OUT sys_emp_package.type_cursor -- 输出结果集
)
IS
v_sqlstr VARCHAR2(2000) ;
v_begin NUMBER:=(p_Current-1)*p_Rows+1;--每页开始的行序号
v_end NUMBER:=p_Current*p_Rows;
BEGINv_sqlstr:='SELECT * FROM (SELECT T.*,rownum rn FROM  (SELECT * FROM '|| p_tablename ||') T WHERE rownum<='||v_end ||')  WHERE rn >='||v_begin;-- 把游标和sql 关联起来OPEN p_CursorList FOR v_sqlstr;
-- 计算总结果记录行数
v_sqlstr:='SELECT COUNT(*) FROM '|| p_tablename ;EXECUTE IMMEDIATE v_sqlstr INTO p_RowCount ;-- 执行SQL 并把结果赋值给 p_RowCountIF MOD(p_RowCount,p_Rows)=0 THENp_PageSum:=p_RowCount/p_Rows;ELSEp_PageSum:=CEIL(p_RowCount/p_Rows);END IF;--关闭游标--CLOSE p_CursorList;  如果打开java程序则ResultSet为NULL
END;
/
4.3. sqlplus 调用方法
set serverout on
-- 每页显示10行,显示第一页的数据
HR@orcl> declare2  cur_out_arg package_hr_emp.type_cursor;3  rec_arg package_hr_emp.type_record;4  v_RowCount NUMBER;5  v_PageSum NUMBER;6  begin8    dbms_output.put_line('------------------------');10    sp_GetPageSizeList_Plsql('employees',10,1,v_RowCount,v_PageSum,cur_out_arg);12    dbms_output.put_line('总结果集行数为:'||v_RowCount||',总页数为:'||v_PageSum);14    loop15       fetch cur_out_arg into rec_arg;16       exit when cur_out_arg%notfound;17       dbms_output.put_line(rec_arg.empno || ' ' || rec_arg.empname || ' ' ||rec_arg.lastname || ' ' || rec_arg.email || ' ' ||rec_arg.phone_number);18    end loop;19  end;20  /
------------------------
总结果集行数为:107,总页数为:11
100 Steven King SKING 515.123.4567
101 Neena Kochhar NKOCHHAR 515.123.4568
102 Lex De Haan LDEHAAN 515.123.4569
103 Alexander Hunold AHUNOLD 590.423.4567
104 Bruce Ernst BERNST 590.423.4568
105 David Austin DAUSTIN 590.423.4569
106 Valli Pataballa VPATABAL 590.423.4560
107 Diana Lorentz DLORENTZ 590.423.5567
108 Nancy Greenberg NGREENBE 515.124.4569
109 Daniel Faviet DFAVIET 515.124.4169PL/SQL procedure successfully completed.-- 每页显示5行,显示第二页的数据
HR@orcl> declare2  cur_out_arg package_hr_emp.type_cursor;3  rec_arg package_hr_emp.type_record;4  v_RowCount NUMBER;5  v_PageSum NUMBER;6  begin8    dbms_output.put_line('------------------------');10    sp_GetPageSizeList_Plsql('employees',5,2,v_RowCount,v_PageSum,cur_out_arg);12    dbms_output.put_line('总结果集行数为:'||v_RowCount||',总页数为:'||v_PageSum);14    loop15       fetch cur_out_arg into rec_arg;16       exit when cur_out_arg%notfound;17       dbms_output.put_line(rec_arg.empno || ' ' || rec_arg.empname || ' ' ||rec_arg.lastname || ' ' || rec_arg.email || ' ' ||rec_arg.phone_number);18    end loop;19  end;20  /
------------------------
总结果集行数为:107,总页数为:22
105 David Austin DAUSTIN 590.423.4569
106 Valli Pataballa VPATABAL 590.423.4560
107 Diana Lorentz DLORENTZ 590.423.5567
108 Nancy Greenberg NGREENBE 515.124.4569
109 Daniel Faviet DFAVIET 515.124.4169PL/SQL procedure successfully completed.
4.4. Java调用分页存储过程
package com.mao;
import java.sql.*;
public class procedurepagesize {public static final String DBDRIVER = "oracle.jdbc.driver.OracleDriver";public static final String DBURL = "jdbc:oracle:thin:@192.168.0.207:1521/FREEPDB1";public static final String USER = "hr";public static final String PASSWORD = "hr";public static void main(String[] args) {try {Class.forName(DBDRIVER);Connection conn = DriverManager.getConnection(DBURL, USER, PASSWORD);Statement stmt = conn.createStatement(); //Statement// 调用分页存储过程 sp_GetPageSizeListSystem.out.println("********调用分页存储过程 ********");String mSQL2 = " {CALL sp_GetPageSizeList(?,?,?,?,?,?) }";CallableStatement callableStatement_pagesize = conn.prepareCall(mSQL2);callableStatement_pagesize.setString(1, "EMPLOYEES");callableStatement_pagesize.setInt(2, 5);//每页显示的条数callableStatement_pagesize.setInt(3, 2);//当前是第几页// 注册总行数callableStatement_pagesize.registerOutParameter(4, oracle.jdbc.OracleTypes.INTEGER);// 注册总页数callableStatement_pagesize.registerOutParameter(5, oracle.jdbc.OracleTypes.INTEGER);callableStatement_pagesize.registerOutParameter(6, oracle.jdbc.OracleTypes.CURSOR);callableStatement_pagesize.execute();//执行int rowCount = callableStatement_pagesize.getInt(4);int pageSum = callableStatement_pagesize.getInt(5);// 结果集ResultSet resultSet_pagesize = (ResultSet) callableStatement_pagesize.getObject(6);System.out.println("总行数:" + rowCount);System.out.println("总页数:" + pageSum);while(resultSet_pagesize.next()) { //移动指针的同时判读是否还有数据行int empno=resultSet_pagesize.getInt(1);String ename=resultSet_pagesize.getString(2);System.out.println("PeaparedStatement class method id ="+empno+", xingm_nameinfo ="+ename);}conn.close();stmt.close();}catch (Exception e){e.printStackTrace();}}
}com.mao.procedurepagesize
********调用分页存储过程 ********
总行数:107
总页数:22
PeaparedStatement class method id =105, xingm_nameinfo =David
PeaparedStatement class method id =106, xingm_nameinfo =Valli
PeaparedStatement class method id =107, xingm_nameinfo =Diana
PeaparedStatement class method id =108, xingm_nameinfo =Nancy
PeaparedStatement class method id =109, xingm_nameinfo =DanielProcess finished with exit code 0

5. 注意事项

  • 在使用分页查询时,一定要指定ORDER BY子句,以确保结果的一致性。
  • 对于大量数据的分页查询,性能可能会成为问题。考虑使用索引优化查询,或者根据业务需求调整分页逻辑(如懒加载、搜索条件过滤等)。
  • 不同的Oracle版本可能在分页查询的支持上有所不同,务必参考对应版本的官方文档。

http://www.ppmy.cn/ops/98087.html

相关文章

C学习(数据结构)-->二叉树

目录 一、树 1、概念与结构 2、相关术语 3、树的表示 孩子兄弟表示法&#xff1a; ​编辑​编辑 二、二叉树 1、概念与结构 2、特殊的二叉树 1&#xff09;满二叉树 2&#xff09;完全二叉树 3、二叉树的存储结构 1&#xff09;顺序存储 2&#xff09;链式结构 一、树…

Docker微服务实战Demo

通过IDEA新建一个微服务模块通过dockerfile发布微服务部署到docker容器 通过IDEA新建一个微服务模块 新建一个spring boot项目modulemvn package打成一个jar包 通过dockerfile发布微服务部署到docker容器 编写dockerfile构建镜像运行容器访问测试 编写dockerfile ## 继承…

深度学习 --- VGG16各层feature map可视化(JupyterNotebook实战)

VGG16模块的可视化 VGG16简介&#xff1a; VGG是继AlexNet之后的后起之秀&#xff0c;相对于AlexNet他有如下特点&#xff1a; 1&#xff0c;更深的层数&#xff01;相对于仅有8层的AlexNet而言&#xff0c;VGG把层数增加到了16和19层。 2&#xff0c;更小的卷积核&#xff01;…

无线数传模块有啥特点?

一 、 模块特点  支持 RS485RTU 、RS232、UART 标准协议  AES加密  供电电压DC4.5V——5.5V  工作频段 410~525MHz, 免申请频段  标准配置提供多达 115信道 …

ArcGIS如何将投影坐标系转回为地理坐标系

有时候两个数据&#xff0c;一个为投影坐标系&#xff0c;另一个为地理坐标系时&#xff0c;在GIS软件中位置无法叠加到一起&#xff0c;这需要将两个或多个数据的坐标系统一&#xff0c;可以直接将地理坐标系的数据进行投影&#xff0c;或将投影坐标系转为地理坐标系。下面介绍…

【时时三省】c语言例题----华为机试题< 数字颠倒>

目录 1,题目 描述 输入描述: 输出描述: 示例1 2,代码

[星瞳科技]OpenMV有哪些合适的配件?

LCD的使用 视频教程7 - LCD显示屏的使用&#xff1a;OpenMV使用LCD显示屏 | 星瞳科技 在IDE中运行下面的代码&#xff1a; 此代码适用于4.5.1至最新的固件版本。 # LCD显示例程 # # 注意&#xff1a;要运行这个例子&#xff0c;你需要一个用于OpenMV的LCD扩展板。 # # LCD扩…

TCP网络编程

1.tcp模型的特点&#xff1a;1&#xff09;面向传输 2&#xff09;可靠传输 3&#xff09;面向字节流程 数据无误、数据无丢失、数据无失序、数据无重复 2.适用于&#xff1a;1&#xff09;对传输质量要求高的&#xff0c;且有可能需要传输大量数据的通信 2&#xff09;在需…