在Oracle数据库中实现分页功能通常需要使用ROWNUM或ROW_NUMBER()函数。下面我将介绍几种实现分页的存储过程方法。
CREATE OR REPLACE PROCEDURE paging_query(
p_table_name IN VARCHAR2, -- 表名
p_fields IN VARCHAR2, -- 查询字段
p_page_size IN NUMBER, -- 每页记录数
p_page_no IN NUMBER, -- 当前页码
p_order_by IN VARCHAR2, -- 排序字段
p_total_records OUT NUMBER, -- 总记录数
p_total_pages OUT NUMBER, -- 总页数
p_cursor OUT SYS_REFCURSOR -- 返回结果集
)
IS
v_sql VARCHAR2(2000);
v_start NUMBER := (p_page_no - 1) * p_page_size + 1;
v_end NUMBER := p_page_no * p_page_size;
BEGIN
-- 计算总记录数
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || p_table_name INTO p_total_records;
-- 计算总页数
p_total_pages := CEIL(p_total_records / p_page_size);
-- 分页查询
v_sql := 'SELECT * FROM (
SELECT A.*, ROWNUM rn FROM (
SELECT ' || p_fields || ' FROM ' || p_table_name ||
' ORDER BY ' || p_order_by ||
') A WHERE ROWNUM <= ' || v_end ||
') WHERE rn >= ' || v_start;
-- 打开游标返回结果
OPEN p_cursor FOR v_sql;
END paging_query;
/
CREATE OR REPLACE PROCEDURE paging_query_row_number(
p_table_name IN VARCHAR2,
p_fields IN VARCHAR2,
p_page_size IN NUMBER,
p_page_no IN NUMBER,
p_order_by IN VARCHAR2,
p_total_records OUT NUMBER,
p_total_pages OUT NUMBER,
p_cursor OUT SYS_REFCURSOR
)
IS
v_sql VARCHAR2(2000);
v_start NUMBER := (p_page_no - 1) * p_page_size + 1;
v_end NUMBER := p_page_no * p_page_size;
BEGIN
-- 计算总记录数
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || p_table_name INTO p_total_records;
-- 计算总页数
p_total_pages := CEIL(p_total_records / p_page_size);
-- 分页查询
v_sql := 'SELECT * FROM (
SELECT ' || p_fields || ',
ROW_NUMBER() OVER (ORDER BY ' || p_order_by || ') AS rn
FROM ' || p_table_name ||
') WHERE rn BETWEEN ' || v_start || ' AND ' || v_end;
-- 打开游标返回结果
OPEN p_cursor FOR v_sql;
END paging_query_row_number;
/
CREATE OR REPLACE PROCEDURE paging_query_12c(
p_table_name IN VARCHAR2,
p_fields IN VARCHAR2,
p_page_size IN NUMBER,
p_page_no IN NUMBER,
p_order_by IN VARCHAR2,
p_total_records OUT NUMBER,
p_total_pages OUT NUMBER,
p_cursor OUT SYS_REFCURSOR
)
IS
v_sql VARCHAR2(2000);
v_offset NUMBER := (p_page_no - 1) * p_page_size;
BEGIN
-- 计算总记录数
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || p_table_name INTO p_total_records;
-- 计算总页数
p_total_pages := CEIL(p_total_records / p_page_size);
-- 分页查询(12c及以上版本)
v_sql := 'SELECT ' || p_fields || ' FROM ' || p_table_name ||
' ORDER BY ' || p_order_by ||
' OFFSET ' || v_offset || ' ROWS FETCH NEXT ' || p_page_size || ' ROWS ONLY';
-- 打开游标返回结果
OPEN p_cursor FOR v_sql;
END paging_query_12c;
/
DECLARE
v_total_records NUMBER;
v_total_pages NUMBER;
v_cursor SYS_REFCURSOR;
v_empno employees.empno%TYPE;
v_ename employees.ename%TYPE;
BEGIN
-- 调用分页存储过程
paging_query(
p_table_name => 'employees',
p_fields => 'empno, ename, job, sal',
p_page_size => 10,
p_page_no => 2,
p_order_by => 'empno',
p_total_records => v_total_records,
p_total_pages => v_total_pages,
p_cursor => v_cursor
);
-- 输出分页信息
DBMS_OUTPUT.PUT_LINE('总记录数: ' || v_total_records);
DBMS_OUTPUT.PUT_LINE('总页数: ' || v_total_pages);
-- 处理结果集
DBMS_OUTPUT.PUT_LINE('第2页数据:');
LOOP
FETCH v_cursor INTO v_empno, v_ename;
EXIT WHEN v_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename);
END LOOP;
CLOSE v_cursor;
END;
/
以上存储过程可以根据实际需求进行修改和优化。