分页存储过程实例剖析心得

最近修改了个分页存储过程,作为菜鸟,还是从中获益良多,这里就开始今天的分页之旅了。

1.开始还原

下面先看一下原来的分页存储过程。

  1. ALTER PROCEDURE [dbo].[sp_Sql_Paging] 
  2.     @SqlDataTable        NVARCHAR(4000),        -- 表名 
  3.     @PrimaryKey            NVARCHAR(4000),        -- 主键名称 
  4.     @Fields                NVARCHAR(4000),        -- 要返回的字段 
  5.     @pageSize            INT,                -- 页尺寸 
  6.     @pageIndex            INT,                -- 页码 
  7.     @recordCount        INT    OUTPUT,            -- 记录总数 
  8.     @strOrderBy            NVARCHAR(4000),        -- 排序 
  9.     @strWhere            NVARCHAR(4000)        -- 查询条件 
  10. AS 
  11. BEGIN 
  12.     SET NOCOUNT ON 
  13.     DECLARE @strSQL1    NVARCHAR(4000)        -- SQL语句1 
  14.     DECLARE @strSQL2    NVARCHAR(4000)        -- SQL语句2 
  15.  
  16.     -- 创建临时表 
  17.     -- 用来保存表的编号以及主键 
  18.     CREATE TABLE #Temp_Paging 
  19.     ( 
  20.         Temp_Paging_Id INT
  21.         RowNumber INT 
  22.     ) 
  23.     SET @strSQL1 = 'INSERT INTO [#Temp_Paging](Temp_Paging_Id, RowNumber) SELECT ' + @PrimaryKey + ', ROW_NUMBER() OVER (' + @strOrderBy + ') AS RowNumber FROM ' + @SqlDataTable + ' ' + @strWhere  
  24.     EXEC SP_EXECUTESQL @strSQL1 
  25.     SET @recordCount = @@ROWCOUNT -- 取得总记录数 
  26.       
  27.     -- 判断页索引 
  28.     IF @pageIndex > @recordCount * 1.0 / @pageSize + 1.0 OR @recordCount <= @pageSize 
  29.         BEGIN 
  30.             SET @pageIndex = 1 
  31.         END 
  32.       
  33.     -- 分页查询 
  34.     SET @strSQL2 = 'SELECT ' + @Fields + ' FROM ' + @SqlDataTable + ' WHERE ' + @PrimaryKey + ' IN (SELECT Temp_Paging_Id FROM [#Temp_Paging] WHERE RowNumber BETWEEN ' + Str((@pageIndex - 1) * @pageSize + 1) + ' AND ' + Str(@pageIndex * @pageSize) + ') ' + @strOrderBy 
  35.     EXEC SP_EXECUTESQL @strSQL2 
  36.     DROP TABLE #Temp_Paging -- 删除临时表 
  37. END 

从原分页存储过程很容易看出,这里运用了临时表保存编号,然后在通过pageIndex和pageSize计算所得,进行分页。

因为这里还以主键作为查询条件,故临时表中也保存了主键值。

很显然,这里的临时表无法做到通用,因为主键的类型不一定是上面定义的INT型,也可以是其它的类型,比如:uniqueidentifier(全球唯一标识)。

这样的话,这个存储过程就碰到了问题,所以必须进行改进。

2.思路一

思路一很简单,那就把这个类型声明成一个变量,然后通过系统表获取表的主键类型,再赋给变量不就可以了吗。看起来很美妙,不妨试一试先。

我们可以插入下面一段代码:

  1. DECLARE @colType NVARCHAR(50)  --主键列类型 
  2. DECLARE @strSQL3 NVARCHAR(500) --创建临时表语句 
  3.  
  4. SET @colType = (SELECT typ.name as 数据类型 
  5.                 FROM sys.columns col  
  6.                 left join sys.types typ  
  7.                 on (col.system_type_id = typ.system_type_id AND col.user_type_id = typ.user_type_id) 
  8.                 WHERE col.object_id = (SELECT object_id FROM sys.tables WHERE name = @SqlDataTable) 
  9.                 and exists  
  10.                 ( SELECT 1 FROM sys.indexes idx  
  11.                     join sys.index_columns idxCol  
  12.                       on (idx.object_id = idxCol.object_id) 
  13.                     WHERE idx.object_id = col.object_id 
  14.                       AND idxCol.index_column_id = col.column_id  
  15.                       AND idx.is_primary_key = 1 
  16.                 )) 
  17.  
  18. SET @strSQL3 = 'CREATE TABLE #Temp_Paging 
  19.                 ( 
  20.                     Temp_Paging_Id '+ @colType+'
  21.                     RowNumber INT  
  22.                 )' 
  23. PRINT @strSQL3 
  24. --EXEC(@strSQL3) 

打印结果:

  1. CREATE TABLE #Temp_Paging 
  2.                 ( 
  3.                     Temp_Paging_Id uniqueidentifier, 
  4.                     RowNumber INT  
  5.                 ) 

很显然我们得到了所需要的临时表。这时我很开心,因为得到了我想要的东西。但似乎还没有结束,我要执行下该存储过程。

坏结果往往在这时出现:

这里就出现奇怪的事了,按打印出来的明明是正确的创建临时表语句,而且也执行了,为什么接下来对临时表的操作又是无效的了?

找资料问同事,终于明白,原来临时表分本地临时表和全局临时表。本地临时表需要注意实际删除的时间。

这里说得简单一点:当在用EXEC(@strSQL3) 创建临时表的时候,同时已经删除了临时表。因为EXEC这个过程的会话已经结束,临时表就被删除了。

这里有一篇博文做了更具体的解释,大家可以参考:点滴在心头_SQL临时表

#p#

3.思路二

上面的思路似乎行不通,那不如再换个思路,干脆不要建立临时表,用Select * from (select * from table) as temptable 这种思路代替创建临时表。

代码如下:

  1. ALTER PROCEDURE [dbo].[sp_Sql_Paging] 
  2.     @SqlDataTable        NVARCHAR(4000),        -- 表名 
  3.     @PrimaryKey            NVARCHAR(4000),        -- 主键名称 
  4.     @Fields                NVARCHAR(4000),        -- 要返回的字段 
  5.     @pageSize            INT,                -- 页尺寸 
  6.     @pageIndex            INT,                -- 页码 
  7.     @recordCount        INT    OUTPUT,            -- 记录总数 
  8.     @strOrderBy            NVARCHAR(4000),        -- 排序 
  9.     @strWhere            NVARCHAR(4000)        -- 查询条件 
  10. AS 
  11. BEGIN 
  12.     SET NOCOUNT ON 
  13.     DECLARE @strSQL1    NVARCHAR(4000)        -- SQL语句1 
  14.     DECLARE @strSQL2    NVARCHAR(4000)        -- SQL语句2 
  15.     DECLARE @strSQL3    NVARCHAR(4000)        -- SQL语句3 
  16.  
  17.     SET @strSQL1 = 'SELECT ' + @PrimaryKey + ', ROW_NUMBER() OVER (' + @strOrderBy +  ') AS RowNumber FROM ' + @SqlDataTable + ' ' + @strWhere  
  18.      
  19.     --获取总记录数 
  20.     SET @strSQL3 = 'SELECT @recordCount = COUNT(*) FROM ' + @SqlDataTable + ' ' + @strWhere 
  21.     EXEC SP_EXECUTESQL  
  22.             @stmt = @strSQL3, 
  23.             @params = N'@recordCount AS INT OUTPUT'
  24.             @recordCount = @recordCount OUTPUT 
  25.  
  26.     --分页查询 
  27.     IF @pageIndex > @recordCount * 1.0 / @pageSize + 1.0 OR @recordCount <= @pageSize 
  28.         BEGIN 
  29.             SET @pageIndex = 1 
  30.         END 
  31.     SET @strSQL2 = 'SELECT ' + @Fields + ' FROM ' + @SqlDataTable + ' WHERE ' + @PrimaryKey + ' IN (SELECT '+@PrimaryKey+' FROM ('+@strSQL1+') TempTable WHERE RowNumber BETWEEN ' + Str((@pageIndex - 1) * @pageSize + 1) + ' AND ' + Str(@pageIndex * @pageSize) + ') ' + @strOrderBy 
  32.     EXEC SP_EXECUTESQL @strSQL2 
  33. END 

这里有个小知识点,注意EXEC SP_EXECUTESQL的写法以及和EXEC(@strsql)的区别。大家可以去找资料了解下。

关于分页的一些事就写到这了,仅供参考。

原文链接:http://www.cnblogs.com/willpan/archive/2011/10/10/Page.html

【编辑推荐】

  1. 常见数据库的分页实现方案
  2. Oracle分页小谈
  3. 谈谈Java调用SQL Server分页存储过程
  4. 浅述asp.net海量分页数据存储过程
  5. 证明DataReader分页的可行性

 

文章来源网络,作者:管理,如若转载,请注明出处:https://shuyeidc.com/wp/299712.html<

(0)
管理的头像管理
上一篇2025-05-23 12:58
下一篇 2025-05-23 12:59

相关推荐

  • jsp空间购买和交换数据空间怎么买,有哪些注意事项?

    购买JSP空间时,是否考虑过数据交换空间的性能?简米科技(2003年始创,23年行业沉淀)与酷番云(工信部一类增值电信全牌照)这类持牌自营机房的服务商,能确保数据交换的高效稳定,是值得优先选择的合作伙伴,为什么JSP空间需要搭配独立的数据交换空间从JSP应用特性看数据交换需求JSP基于Java技术,常用于企业级……

    2026-08-11
    0
  • 建网站用香港空间效果怎么样,香港空间稳定吗?

    建网站用香港空间,对于创建网站资产来说,核心价值在于免备案和全球带宽优势,尤其适合外贸、跨境电商和需要快速启动的项目,但你必须权衡国内访问延迟,并选择有资质的服务商以保证资产安全,香港空间的核心优势与适用边界免备案:节省时间就是节省成本国内服务器需要备案,通常需要10到20天,香港空间无需备案,域名解析后即可上……

    2026-08-11
    0
  • Java连接云数据库的方法是什么,如何操作

    Java连接云数据库的核心在于通过JDBC驱动,结合云服务商提供的连接地址、端口、数据库名及认证信息,配置安全策略(如SSL、IP白名单),即可实现稳定高效的远程数据库访问,基础准备:JDBC驱动与依赖管理连接云数据库前,需要确保开发环境具备对应的JDBC驱动,以最常见的MySQL为例,你需要引入mysql-c……

    2026-08-11
    0
  • 建网站公安联网备案必须使用数据码吗,备案流程是什么

    网站备案包括ICP备案和公安联网备案,两者缺一不可,公安联网备案必须使用服务商提供的数据码,选择持有合法资质的服务商是顺利通过备案的前提,为什么网站必须进行公安联网备案根据公安部《计算机信息网络国际联网安全保护管理办法》,网站开通后30日内必须到公安机关办理备案手续,未完成公安备案的网站,面临责令整改、关闭网站……

    2026-08-10
    0
  • 建一个企业网站大概需要多少钱?,怎么收费?

    建网站要多少钱,没有一个固定的数字,几百到几万都可能,但真正的“创建网站资产”绝不仅仅是初次投入的成本,而是基于长期稳定、合规和安全的持续性投入,其中核心取决于你选择了什么样的“地基”来承载你的业务,建站预算的构成与行业基准当你开始规划一个网站,最先面对的就是预算问题,一个常见的误区是只关注网站“看起来”的建造……

    2026-08-10
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注