Oracle 过程分页带来比预期更多的行

Posted

技术标签:

【中文标题】Oracle 过程分页带来比预期更多的行【英文标题】:Oracle procedure pagination bringing back more rows than expected 【发布时间】:2021-04-27 01:12:49 【问题描述】:

这是一个用于示例目的的简化程序。我遇到的问题是,当我转到应用程序的下一页时,它会带回 5 个,然后是 10 个,然后是 15 个,然后是 10 个。我每次只想带回 5 个。它似乎发生在日期递减时。

procedure GET_DATA( p_sort_col IN VARCHAR2, p_sort_order IN VARCHAR2,
  p_page_index IN NUMBER DEFAULT null,
  p_page_size IN NUMBER DEFAULT null, p_cursor  out l_cursor)
AS
begin
OPEN p_cursor FOR
    select * from (
select* from (select rownum rn, Name, DateCol, ROW_NUMBER() Over( ORDER BY 
 CASE
        WHEN p_sort_col = 'Name' and p_sort_order = 'asc' THEN
         Name
END ASC,
  CASE 
            WHEN p_sort_col = 'DateCol' and p_sort_order = 'asc' THEN
           DateCol
     END ASC,
CASE 
        WHEN p_sort_col = 'Name' and p_sort_order = 'desc' THEN
         Name
     END DESC,
      CASE 
            WHEN p_sort_col = 'DateCol' and p_sort_order = 'desc' THEN
            DateCol
     END DESC) from gdpr_document_manager_audit  
     ) where  rownum < ((p_page_index * p_page_size) + 1 )         
)WHERE rn >= (((p_page_index-1) * p_page_size));
END GET_DATA;

实际查询

【问题讨论】:

没有排序的分页没有什么意义。 @TheImpaler 它有排序看关键词的顺序? 我只能在ROW_NUMBER() 函数中看到ORDER BY。但是,它不会影响结果集的排序。 @TheImpaler 实际上是。 @TheImpaler 当我进入应用程序的下一页时,它首先对结果集进行排序然后对其进行分页,感谢您的输入,关于分页问题有什么真正有用的建议吗? 【参考方案1】:

我假设

select event_type, doc_page, application_number, 
       document_reference, username, application_year, 
       full_name, date_and_time
  from gdpr_document_manager_audit
 ORDER BY 
   CASE
     WHEN p_sort_col = 'EventType' and p_sort_order = 'asc' THEN event_type 
     WHEN p_sort_col = 'ApplicationYear' and p_sort_order = 'asc' THEN application_year 
     WHEN p_sort_col = 'ApplicationNumber' and p_sort_order = 'asc' THEN application_number 
     WHEN p_sort_col = 'DocumentReference' and p_sort_order = 'asc' THEN doument_reference 
     WHEN p_sort_col = 'Username' and p_sort_order = 'asc' THEN username 
     WHEN p_sort_col = 'Name' and p_sort_order = 'asc' THEN full_name 
   END ASC,
   CASE 
     WHEN p_sort_col = 'DateAndTime' and p_sort_order = 'asc' THEN date_and_time
   END ASC,
   CASE 
     WHEN p_sort_col = 'EventType' and p_sort_order = 'desc' THEN event_type 
     WHEN p_sort_col = 'ApplicationYear' and p_sort_order = 'desc' THEN application_year 
     WHEN p_sort_col = 'ApplicationNumber' and p_sort_order = 'desc' THEN application_number 
     WHEN p_sort_col = 'DocumentReference' and p_sort_order = 'desc' THEN document_reference 
     WHEN p_sort_col = 'Username' and p_sort_order = 'desc' THEN username 
     WHEN p_sort_col = 'Name' and p_sort_order = 'desc' THEN full_name 
 END DESC,
 CASE 
     WHEN p_sort_col = 'DateAndTime' and p_sort_order = 'desc' THEN date_and_time
 END DESC

按照你想要的顺序返回你想要的数据,只是没有分页。为简单起见,我将在下面的答案中将此查询称为#base_query#。如果是这样,并且鉴于您需要支持旧版本的 Oracle,您可以将其转换为分页查询

select * 
  from ( select /*+ FIRST_ROWS(n) */ 
                a.*, ROWNUM rnum 
           from ( #base_query# ) a 
          where ROWNUM <= ((p_page_index * p_page_size) + p_page_size ) ) 
  where rnum  >= (((p_page_index-1) * p_page_size));

使用您对要返回的最小和最大行的计算。您还没有告诉我们您为各种参数传递了什么值。如果我们猜测p_page_index 是第一页的 1(有些人使用基于 0 的索引),那么您可能实际上想要

select * 
  from ( select /*+ FIRST_ROWS(n) */ 
                a.*, ROWNUM rnum 
           from ( #base_query# ) a 
          where ROWNUM <= (p_page_index * p_page_size) 
  where rnum  >= (p_page_index-1) * p_page_size + 1;

因此,如果 p_page_index = 1 和 p_page_size = 10,您将获得第 1 到 10 行。如果 p_page_index = 2 和 p_page_size = 10,您将获得第 11 到 20 行。依此类推。

【讨论】:

还是有同样的问题,问题是分页的计算。 @贾斯汀洞穴 @PaulDocks - 看起来你试图编辑我的回复说你得到了你想要的。但是后来加了评论说还是有问题。 是的,抱歉,也想删除实际的查询。我仍然有同样的问题。问题是分页逻辑。 @贾斯汀洞穴 @PaulDocks - 我对您为参数传递的值做了一些猜测,并更新了我的答案。如果您使用基于 0 的索引,那就不同了。为最小和最大行创建局部变量可能更容易,然后您可以打印出来/检查以进行调试。 1,2,3,4 等用于页面索引,5 用于页面大小每次@JustinCave

以上是关于Oracle 过程分页带来比预期更多的行的主要内容,如果未能解决你的问题,请参考以下文章

加入两个查询会返回比预期更多的行?

Oracle SQL - 从视图中选择比在视图中运行选择更多的行

使用 Oracle 进行分页

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

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

Oracle 分页存储过程