使用Oracle和sql server以及通用分页方法进行分页

时间:2009-01-28 15:44:38

标签: sql sql-server oracle

我想在gridview或html表中实现分页,我将使用ajax填充。我应该如何编写查询以支持分页?例如,如果pagesize为20,当用户单击第3页时,必须在表格中显示41到60之间的行。起初我可以获取所有记录并将它们放入缓存中,但我认为这是错误的方法。因为数据可能非常庞大,数据可能会从其他会话中更改。那么我该如何实现呢?是否有任何通用方式(适用于所有数据库)?

7 个答案:

答案 0 :(得分:17)

正如其他人所建议的那样,您可以在Oracle中使用rownum。这有点棘手,你必须将查询嵌套两次。

例如,分页查询

select first_name from some_table order by first_name

你需要像这样嵌套它

select first_name from
  (select rownum as rn, first_name from
    (select first_name from some_table order by first_name)
  ) where rn > 100  and rn <= 200

原因是rownum在 where子句后确定子命令之前确定。要查看我的意思,您可以查询

select rownum,first_name from some_table order by first_name

你可能会得到

4   Diane
2   Norm
3   Sam
1   Woody

这是因为oracle评估了where子句(在本例中为none),然后分配rownums,然后按first_name对结果进行排序。您必须嵌套查询,以便在对行进行排序后使用已分配的的rownum。

第二个嵌套与如何在where条件下处理rownum有关。基本上,如果您查询“rownum&gt; 100”,那么您将得不到任何结果。这是一个鸡肉和鸡蛋的东西,它不能返回任何行,直到它找到rownum&gt; 100,但因为它没有返回任何行,所以它永远不会增加rownum,因此它永远不会计入100.呃。第二级嵌套解决了这个问题。请注意,此时必须为rownum列添加别名。

最后,您的order by子句必须使查询具有确定性。例如,如果您有John Doe和John Smith,并且您只按名字排序,则两者可以从一次执行查询切换到下一次。

这里有文章http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html 在这里http://www.oracle.com/technology/oramag/oracle/07-jan/o17asktom.html。现在我看到我的帖子有多长,我可能应该刚刚发布这些链接......

答案 1 :(得分:4)

不幸的是,限制查询返回的行范围的方法因DBMS而异:Oracle使用ROWNUM(请参阅ocdecio的答案),但ROWNUM在SQL Server中不起作用。

也许您可以使用一个函数来封装这些差异,该函数接受给定的SQL语句以及第一个和最后一个行号,并为目标DBMS生成适当的paginatd SQL - 例如:

sql = paginated ('select empno, ename from emp where job = ?', 101, 150)

会返回

'select * from (select v.*, ROWNUM rn from ('
 + theSql
 + ') v where rownum < 150) where rn >= 101'

for Oracle和SQL Server的其他内容。

但请注意,Oracle解决方案是在您需要处理的结果中添加新的列RN。

答案 2 :(得分:1)

我相信两者都有一个ROWNUM分析函数。使用它,你就会完全相同。

在Oracle中,它是here

ROW_NUMBER

是的,只是确认ROW_NUMBER在两者中都是相同的功能。

答案 3 :(得分:1)

“因为......数据可以从其他会话中更改。” 你想要为此做些什么?

例如,用户在10:30获取“最新”十行。

在10:31,添加了3个新行(因此用户查看的10个不再是最新的行。)

在10:32,用户请求“下一个”十个条目。

你想要那个新的套装包括从8/9/10到2013年12月12日被撞的那三个吗? 如果没有,在Oracle中您可以选择10:30时的数据

SELECT * FROM table_1 as of timestamp (timestamp '2009-01-29 10:30:00'); 

您仍然需要row_number逻辑,例如

 select * from
    (SELECT a.*, row_number() over (order by hire_date) rn
    FROM hr.employees as of timestamp (timestamp '2009-01-29 10:30:00') a)
 where rn between 10 and 19

答案 4 :(得分:1)

select * 
  from ( select /*+ FIRST_ROWS(n) */   a.*,
      ROWNUM rnum 
      from ( your_query_goes_here, 
      with order by ) a 
      where ROWNUM <= 
      :MAX_ROW_TO_FETCH ) 
where rnum  >= :MIN_ROW_TO_FETCH;

第1步:按订单查询

第2步:select a.*, ROWNUM rnum from ()a where ROWNUM <=:MAX_ROW_TO_FETCH

第3步:select * from ( ) where rnum >= :MIN_ROW_TO_FETCH; 把1分2分和2分3分

答案 5 :(得分:0)

如果预期的数据集很大,我建议创建一个临时表,一个视图或一个快照(物化视图)来存储查询结果+使用ROWNUM或ROW_NUMBER分析函数检索的行号。之后,您可以使用行号范围简单地查询此临时存储。 基本上,您需要将实际数据提取与分页分开。

答案 6 :(得分:0)

没有统一的方法来确保跨各种RDBMS产品进行分页。 Oracle为您提供了rownum,您可以在where子句中使用它:

where rownum < 1000

SQL Server为您提供了row_id()函数,可以使用类似于Oracle的rownum。但是,在SQL Server 2005之前,row_id()不可用。