存储过程sql server中的分页

Posted

技术标签:

【中文标题】存储过程sql server中的分页【英文标题】:Pagination in stored procedure sql server 【发布时间】:2015-02-20 06:39:37 【问题描述】:

我已经为存储过程实现了分页,它一个接一个地显示 2 个表记录。分页逻辑适用于第一个表记录,但第二个表没有相应地显示记录。

这是我的存储过程。我哪里错了?

CREATE PROCEDURE sp_PagedItems
(@Page int,
 @RecsPerPage int)
AS
   SET NOCOUNT ON

   CREATE TABLE #TempItems
   (
        ID int IDENTITY,
        Name varchar(50),
        Price int
   )  

   INSERT INTO #TempItems (Name, Price)
      SELECT 
         Name, Price 
      FROM tblItems 
      ORDER BY Price  

   CREATE TABLE #TempItems1
   (
        ID int IDENTITY,
        Name varchar(50),
        Price int
   ) 

   INSERT INTO #TempItems1 (Name, Price)
      SELECT Name, Price  
      FROM tblItems1 
      ORDER BY Price 

   DECLARE @FirstRec int, @LastRec int

   SELECT @FirstRec = (@Page - 1) * @RecsPerPage
   SELECT @LastRec = (@Page * @RecsPerPage + 1)

   SELECT *
   FROM #TempItems 
   WHERE ID > @FirstRec AND ID < @LastRec 

   SELECT *
   FROM #TempItems1 
   WHERE ID > @FirstRec AND ID < @LastRec 

   -- Turn NOCOUNT back OFF
   SET NOCOUNT OFF

执行它:

Exec sp_PagedItems 1, 10

第一个表在第 1 页显示 10 条记录,而第二个表仅显示 7 条记录。

【问题讨论】:

第二个表有10条记录吗?或者在#FirstRec 和@LAstRec 之间有 10 个 ID 两个表都有1000+条记录。 旁注:您应该为您的存储过程使用sp_ 前缀。微软有reserved that prefix for its own use (see Naming Stored Procedures),你确实会在未来某个时候冒着名称冲突的风险。 It's also bad for your stored procedure performance。最好只是简单地避免 sp_ 并使用其他东西作为前缀 - 或者根本不使用前缀! @Aswini,好的,您有 1000 多条记录,但参数 FirstRec 和 LastRec 之间有 10 条记录 为你的表命名#TempItems 和#TempItems1 听起来像是等待发生的错误。如果您真的没有找到更好的名字,为什么至少不将它们称为 1 和 2? 【参考方案1】:

如果您使用的是 SQL Server 2012 或更高版本,请尝试使用 OFFSET FETCH 语句

https://technet.microsoft.com/en-us/library/gg699618%28v=sql.110%29.aspx

【讨论】:

【参考方案2】:

使用 SQL 对表中的数据进行分页使用系统生成的 ID 几乎总是会遇到问题。

您实际如何进行分页将取决于 RDBMS 支持的 SQl,但适用于任何地方的通用方法如下:

    在适当的地方订购等进行正常选择 从一开始就循环浏览记录,边走边算 当您到达 (pageCount * recordsPerPage)+1 时,开始收集记录 当您到达 (pageCount+1) * recordsPerPage 时,停止收集记录

这听起来非常低效,但通常并不像看起来那么糟糕,因为如果您允许排序,那么用户所追求的记录通常靠近前面。

【讨论】:

【参考方案3】:

是的,这可能行不通,原因是相同的 id 或 id 存在于多个条目中。

要解决,插入临时表后,在选择中必须使用ROW_NUMBER() OVER (order by id ) AS rowID,我所做的是:

--set end page no. from calculation of pageno * pagesize
 SELECT   
   @start = CASE WHEN @pageindex > 1   
          THEN   
      ((@PageIndex-1)*@PageSize)+1    
       ELSE   
      @PageIndex   
     END   

 SET @end = @PageIndex*@PageSize  
-- use cte 
;WITH CTE AS    
(    
 your select query 
  --suppose activityID is a column in select query , we used for row_number
)    
--now use cte with rownumber filter
select * from  
(  
 SELECT ROW_NUMBER() OVER (ORDER BY activityID DESC) as rowID,    
 *, noofRows= (SELECT count(activityID) FROM CTE)    
 FROM CTE   
 where CTE.activityTargetID is not null  
) cte  
WHERE    
 rowID between @start AND @end   

ORDER BY CTE.activityID DESC  

【讨论】:

以上是关于存储过程sql server中的分页的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 分页查询存储过程

老码农怀旧一个简单好用的分页存储过程

将数据从 MS Sql Server 存储过程导出到 excel 文件

Sql分页存储过程

基于Dapper的分页实现,支持筛选,排序,结果集总数,非存储过程

sql server 分页存储过程