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

1.开始还原 下面先看一下原来的分页存储过程。


代码如下:

ALTER PROCEDURE [dbo].[sp_Sql_Paging]
(
@SqlDataTable NVARCHAR(4000), -- 表名
@PrimaryKey NVARCHAR(4000), -- 主键名称
@Fields NVARCHAR(4000), -- 要返回的字段
@pageSize INT, -- 页尺寸
@pageIndex INT, -- 页码
@recordCount INT OUTPUT, -- 记录总数
@strOrderBy NVARCHAR(4000), -- 排序
@strWhere NVARCHAR(4000) -- 查询条件
)
AS
BEGIN
SET NOCOUNT ON
DECLARE @strSQL1 NVARCHAR(4000) -- SQL语句1
DECLARE @strSQL2 NVARCHAR(4000) -- SQL语句2

-- 创建临时表
-- 用来保存表的编号以及主键
CREATE TABLE #Temp_Paging
(
Temp_Paging_Id INT,
RowNumber INT
)
SET @strSQL1 = 'INSERT INTO [#Temp_Paging](Temp_Paging_Id, RowNumber) SELECT ' + @PrimaryKey + ', ROW_NUMBER() OVER (' + @strOrderBy + ') AS RowNumber FROM ' + @SqlDataTable + ' ' + @strWhere
EXEC SP_EXECUTESQL @strSQL1
SET @recordCount = @@ROWCOUNT -- 取得总记录数

-- 判断页索引
IF @pageIndex > @recordCount * 1.0 / @pageSize + 1.0 OR @recordCount <= @pageSize
BEGIN
SET @pageIndex = 1
END

-- 分页查询
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
EXEC SP_EXECUTESQL @strSQL2
DROP TABLE #Temp_Paging -- 删除临时表
END

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

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

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

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

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

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


代码如下:

DECLARE @colType NVARCHAR(50) --主键列类型
DECLARE @strSQL3 NVARCHAR(500) --创建临时表语句

SET @colType = (SELECT typ.name as 数据类型
FROM sys.columns col
left join sys.types typ
on (col.system_type_id = typ.system_type_id AND col.user_type_id = typ.user_type_id)
WHERE col.object_id = (SELECT object_id FROM sys.tables WHERE name = @SqlDataTable)
and exists
( SELECT 1 FROM sys.indexes idx
join sys.index_columns idxCol
on (idx.object_id = idxCol.object_id)
WHERE idx.object_id = col.object_id
AND idxCol.index_column_id = col.column_id
AND idx.is_primary_key = 1
))

SET @strSQL3 = 'CREATE TABLE #Temp_Paging
(
Temp_Paging_Id '+ @colType+',
RowNumber INT
)'
PRINT @strSQL3
--EXEC(@strSQL3)

打印结果:


代码如下:

CREATE TABLE #Temp_Paging
(
Temp_Paging_Id uniqueidentifier,
RowNumber INT
)

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

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

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

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

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

3.思路二

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

代码如下:


代码如下:

ALTER PROCEDURE [dbo].[sp_Sql_Paging]
(
@SqlDataTable NVARCHAR(4000), -- 表名
@PrimaryKey NVARCHAR(4000), -- 主键名称
@Fields NVARCHAR(4000), -- 要返回的字段
@pageSize INT, -- 页尺寸
@pageIndex INT, -- 页码
@recordCount INT OUTPUT, -- 记录总数
@strOrderBy NVARCHAR(4000), -- 排序
@strWhere NVARCHAR(4000) -- 查询条件
)
AS
BEGIN
SET NOCOUNT ON
DECLARE @strSQL1 NVARCHAR(4000) -- SQL语句1
DECLARE @strSQL2 NVARCHAR(4000) -- SQL语句2
DECLARE @strSQL3 NVARCHAR(4000) -- SQL语句3

SET @strSQL1 = 'SELECT ' + @PrimaryKey + ', ROW_NUMBER() OVER (' + @strOrderBy + ') AS RowNumber FROM ' + @SqlDataTable + ' ' + @strWhere

--获取总记录数
SET @strSQL3 = 'SELECT @recordCount = COUNT(*) FROM ' + @SqlDataTable + ' ' + @strWhere
EXEC SP_EXECUTESQL
@stmt = @strSQL3,
@params = N'@recordCount AS INT OUTPUT',
@recordCount = @recordCount OUTPUT

--分页查询
IF @pageIndex > @recordCount * 1.0 / @pageSize + 1.0 OR @recordCount <= @pageSize
BEGIN
SET @pageIndex = 1
END
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
EXEC SP_EXECUTESQL @strSQL2
END

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

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

(0)

相关推荐

  • asp.net结合aspnetpager使用SQL2005的存储过程分页

    SQL2005的存储过程: 复制代码 代码如下: set ANSI_NULLS ON set QUOTED_IDENTIFIER ON go ALTER PROCEDURE [dbo].[P_GetPagedReCord] (@startIndex INT, -- 开始索引号 @endindex INT, -- 结束索引号 @tblName varchar(255), -- 表名 @fldName varchar(255), -- 显示字段名 @OrderfldName varchar(255)

  • asp.net利用存储过程和div+css实现分页(类似于博客园首页分页)

    首先声明以下几点: 1.也许讲解有点初级,希望高手不要"喷"我,因为我知道并不是每一个人都是高手,我也怕高手们说我装13,小生不才: 2.如有什么不对的地方,还希望大家指出,一定虚心学习: 3.本文属于作者原创,尊重他人劳动成果,转载请注明作者,谢谢. 下面开讲: 首先说下思路,写一个存储过程,我也找了一个存储过程,不过不是我写的,出处:http://www.cnblogs.com/zhongweiv/archive/2011/10/31/JqueryPagination.html 这

  • asp.net安全、实用、简单的大容量存储过程分页第1/2页

    基本上我下面要讲述的侧重点是如何使用,因为其实分页存储过程网上很多,如果你懒得找,那么可以直接使用下面这个我经过测试,并通过修改,网上评价都比较高的分页存储过程. 这个分页主要优点如下: 1.大容量下的数据分页,我的测试数据是520W. 2.我结合aspnetpager控件,使得使用起来更加方便. 3.为了结构清晰,实用3层. 4.安全,你就放心的用吧.SQL注入的问题在这里你可以放心了.网上有文章说只要存储过程是用sql拼接的就存在sql注入的问题,并且直接在sql查询分析器中测试了注入的情况

  • asp.net 结合mysql存储过程进行分页代码

    不过在网上找了一些,发现都有一个特点--就是不能传出总记录数,干脆自己研究吧.终于,算是搞出来了,效率可能不是很好,但是我也觉得不错了.贴代码吧直接:也算是对自己学习mysql的一个记录. 复制代码 代码如下: CREATE PROCEDURE p_pageList ( m_pageNo int , m_perPageCnt int , m_column varchar(1000) , m_table varchar(1000) , m_condition varchar(1000), m_or

  • asp.net 数据访问层 存储过程分页语句

    所以最好在数据访层分页,如果这样就要使用存储过程来分页.以下是以pubs 数据库中的employee表为例来进行数据分页的存储过程,你可以参考它根据实际情况来创建自己的存储过程. 注:@pageindex 数据页的索引,@dataperpage 每页的记录数目,@howmanyrecords 用来获取总的记录数. 复制代码 代码如下: create proc getdata @pageindex int,@dataperpage int,@howmanyrecords int output as

  • asp.net中如何调用sql存储过程实现分页

    首先看下面的代码创建存储过程 1.创建存储过程,语句如下: CREATE PROC P_viewPage @TableName VARCHAR(200), --表名 @FieldList VARCHAR(2000), --显示列名,如果是全部字段则为* @PrimaryKey VARCHAR(100), --单一主键或唯一值键 @Where VARCHAR(2000), --查询条件 不含'where'字符,如id>10 and len(userid)>9 @Order VARCHAR(100

  • asp.net 分页存储过程实例剖析心得

    1.开始还原 下面先看一下原来的分页存储过程. 复制代码 代码如下: ALTER PROCEDURE [dbo].[sp_Sql_Paging] ( @SqlDataTable NVARCHAR(4000), -- 表名 @PrimaryKey NVARCHAR(4000), -- 主键名称 @Fields NVARCHAR(4000), -- 要返回的字段 @pageSize INT, -- 页尺寸 @pageIndex INT, -- 页码 @recordCount INT OUTPUT,

  • ASP.Net分页的分页导航实例

    Asp.Net分页可以设置分页的首页.上一页.下一页.尾页在前台显示的链接文本.这里只是提及简单功能,深入研究剖析其原理就更得心应手了. //containerId 导航的目标容器,建议使用span标签 //url 默认为XXX.XX?pagenum= //curPage 当前的页码 //maxSection 最大的分段数(一段里面最大的页数) //totalPage 总共的页数 function Navigate(containerId,url,curPage,maxSection, tota

  • asp.net分页控件使用详解【附实例下载】

    一.说明 AspNetPager.dll这个分页控件主要用于asp.net webform网站,现将整理代码如下 二.代码 1.首先在测试页面Default.aspx页面添加引用 <%@ Register Assembly="AspNetPager" Namespace="Wuqi.Webdiyer" TagPrefix="webdiyer" %> 2.写一个Repeater列表控件用于显示数据 <asp:Repeater ID

  • 通用分页存储过程,源码共享,大家共同完善

    好久没有上来写点东西了,今天正好有空,共享一些个人心得,就是关于分页的存储过程,这个问题应该是老生重谈了,网上的通用存储过程的类型已经够多了,但是,好象看到的基本上不能够满足一些复杂的SQL语句的分页(也可能是我不够见多识广啊,呵呵),比如下面这句:  select '' as CheckBox, A.TargetID, A.TargetPeriod, Convert(varchar(10), B.BeginDate, 120) as BeginDate,      Convert(varcha

  • 分页存储过程(一)使用sql2005的新函数构造分页存储过程

    其实在很多时候设计的度还是要把握的,不至于让自己陷入[非要把它设计成万能的分页存储过程]的怪圈中才是最重要的,因为我们还要留出时间还解决其他的很多问题,个人认为适度就可以了,留出一定的空间.也因为万能是不存在的,万物在一定的范畴之内都是合理的,出了范畴可能就没有合理的了. 分页存储过程大致有下列几种 1. 利用Not in 和select top 2. 利用id大于多少和select top 3. 利用sql中的游标 4.临时表 可以参看网上的以下链接 C#中常用的分页存储过程小结http://

  • [数据库] 通用分页存储过程第1/5页

    分页存储过程共有四种方式可以实现,行计数.游标.升序-降序.子查询 我记得曾经有人测试过这四种方式的效率分别是 从性能最好到最差的顺序进行的--行计数.游标.升序-降序.子查询 以下是我收集的一些资料供大家参考 QUOTE: 原文地址:http://www.codeproject.com/aspnet/PagingLarge.asp 作者:Jasmin Muharemovic  译者:Tony Qu 下载: 介绍 在Web应用程序中,对一个大数据库结果集进行分页已经是一个家喻户晓的问题了.简单的

  • AspNetPager+GridView实现分页的实例代码

    .框架是.NET Framework 4.0.一共为三个部分: 前台页面设计代码.前台页面程序代码.css样式.其中数据库连接操作用了DB类(连接语句),SQLHelper(微软的数据库操作类)效果图: 前台页面设计代码 复制代码 代码如下: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="TestWebSit

  • ASP开发中存储过程应用全接触

    ASP开发中存储过程应用全接触        ASP与存储过程(Stored Procedures)的文章不少,但是我怀疑作者们是否真正实践过.我在初学时查阅过大量相关资料 ,发现其中提供的很多方法实际操作起来并不是那么回事.对于简单的应用,这些资料也许是有帮助的,但仅限于此,因为 它们根本就是千篇一律,互相抄袭,稍微复杂点的应用,就全都语焉不详了. 现在,我基本上通过调用存储过程访问SQL Server,以下的文字都是实践的总结,希望对大家能有帮助. 存储过程就是作为可执行对象存放在数据库中的

  • 邹建的分页存储过程改了一下

    邹建的分页存储过程--改了一下  因为邹建的分页存储过程不能返回记录总数,所以每次分页还又要统计一次,所以自己在里面加了个返回记录数,这下就好用了. @iPageCount int OUTPUT  --定义输出变量,放在@QueryStr上面 .... exec('select'+@FdShow+'from'+@QueryStr+@FdOrder) --统计记录数,放在--如果显示第一页...上面 Select @iPageCount = @@rowcount 调用方法(ASP): MyConS

随机推荐