在 oracle 中使用存储过程进行分页和排序

Posted

技术标签:

【中文标题】在 oracle 中使用存储过程进行分页和排序【英文标题】:Paging and sorting using a stored procedure in oracle 【发布时间】:2014-09-10 03:49:32 【问题描述】:

我创建了一个用于分页的存储过程。现在我正在寻找列排序。

我的工作分页存储过程:

PROCEDURE paging (PageSize     IN     INT,
                  PageIndex    IN     INT,
                  SortColumn   IN     VARCHAR,
                  PageData        OUT Page) AS
    FirstIndex   INT;
    LastIndex    INT;
    SortCol      VARCHAR;
BEGIN
    LastIndex := PageSize * (PageIndex + 1);
    FirstIndex := LastIndex - PageSize + 1;
    SortCol := SortColumn;

    OPEN PageData FOR
        SELECT *
          FROM (SELECT a.*, ROWNUM AS rnum
                  FROM (  SELECT *
                            FROM table_name
                        ORDER BY SortCol) a
                 WHERE ROWNUM <= LastIndex)
         WHERE rnum >= FirstIndex;
END paging;
/

【问题讨论】:

将您的 ORDER BY 子句添加到最里面的子查询,即(SELECT * form table) 将变为(SELECT * form table ORDER BY transactionDate) 您能否修复您的示例代码:在Open PageData .... 中,您有三个右括号。但只有两个开口。 @cha 如何在 oracle 中使 ORDER BY transactionDate DESC 参数化那些是我们必须传递其值的输入参数 【参考方案1】:

我建议您使用名为 Dynamic SQL (Oracle Docs) 的绝妙功能。

我还修改了您的 SQL 查询并使用 ROW_NUMBER() 而不是 rownum。与后者相比,它是一种对输出行进行排序和编号的更稳健的方法。

我还从您的 PL/SQL 中删除了一些我认为不需要的变量:

PROCEDURE paging (PageSize     IN     INT,
                  PageIndex    IN     INT,
                  SortColumn   IN     VARCHAR2, -- Assuming this always contains
                                                -- the ordering column name
                  PageData        OUT Page) AS
    FirstIndex   INT;
    LastIndex    INT;
    v_sql        VARCHAR2(4000);
BEGIN
    LastIndex := PageSize * (PageIndex + 1);
    FirstIndex := LastIndex - PageSize + 1;

    v_sql :=  'SELECT *'
            ||'  FROM (SELECT a.*,'
            ||'              ROW_NUMBER() '
            ||'                OVER (ORDER BY ' || SortColumn || ') AS rnum'
            ||'          FROM table_name a)'
            ||' WHERE rnum BETWEEN FirstIndex AND LastIndex';

    OPEN PageData FOR v_sql;

END paging;
/

【讨论】:

很好的答案。 ORDER BY SortColumn 是否需要动态 SQL 是的。否则您将如何传递列的名称?对列的索引进行投标在 Oracle 中不起作用(我怀疑,在其他数据库中也是如此)。因此,您需要将列名传递给查询,因此您需要动态 SQL,将列名连接到查询中(而不是像占位符那样绑定)。 我就是这么想的。但由于 OP 没有使用动态 SQL,我认为可能有一些技巧可以做其他事情。感谢您的回复。【参考方案2】:

这个 SP 独自完成了 Oracle 中的所有三件事,Paging, Sorting and Filtering 的记录。

create or replace procedure GetResults 
(
 p_userId In Number,
 p_dueDateFrom In Date,
 p_dueDateTo in Date,
 p_durationMax in Number,
 p_durationMin in Number,
 p_sortColumn In Varchar2,
 p_sortOrder In Varchar2,
 p_pageSize In Number,
 p_pageIndex in number,
 cv_1 OUT SYS_REFCURSOR
)
as 
v_FirstIndex   NUMBER;
v_LastIndex    NUMBER;
begin
-- Paging
  v_LastIndex := p_pageSize * (p_pageIndex + 1);
  v_FirstIndex := v_LastIndex - p_pageSize + 1;

 OPEN cv_1 FOR 

  SELECT * FROM (SELECT a.*, ROWNUM AS rnum
              FROM (Select * From Newjob nj Where nj.userId = p_userId  
               -- Filtering
             And ((p_dueDateFrom IS NULL AND p_dueDateTo Is NULL) OR 
                  (nj.Due_Date >= p_dueDateFrom and nj.Due_Date <= p_dueDateTo)
                 )
             And ((p_durationMax IS NULL AND p_durationMin Is NULL) OR 
                  (nj.Duration >= p_durationMax and nj.Duration <= p_durationMin)
                 )   
             -- Sorting     
            order by   
            Case when p_sortOrder = 'Ascending' And p_sortColumn = 'DUE_DATE' then  nj.Due_Date End,
            Case When p_sortOrder = 'Ascending' And p_sortColumn = 'DURATION' then nj.DURATION end,     
            Case when p_sortOrder = 'Descending' And p_sortColumn = 'DUE_DATE' then  nj.Due_Date End desc,
            Case When p_sortOrder = 'Descending' And p_sortColumn = 'DURATION' then nj.DURATION end desc)a
   WHERE ROWNUM <= v_LastIndex)    
   WHERE rnum >= v_FirstIndex;
end;

【讨论】:

以上是关于在 oracle 中使用存储过程进行分页和排序的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式在 ASP.NET 4.0 GridView 上启用分页和排序?

使用Oracle的rownum或者存储过程分页的详细例子(jsp)~新手

使用 ASP.Net MVC 对网格进行分页和排序

如何对分布式数据进行排序和分页?

SQL 分页查询存储过程中order by 后面不能传变量的问题怎么解决

分页和排序问题