--/*-----存储过程 分页处理 SW 2005-03-28创建 -------*/
--/*----- 对数据进行了2分处理使查询前半部分数据与查询后半部分数据性能相同 -------*/
--/*-----存储过程 分页处理  2005-04-21修改 添加Distinct查询功能-------*/
--/*-----存储过程 分页处理  2005-05-18修改 多字段排序规则问题-------*/
--/*-----存储过程 分页处理  2005-06-15修改 多字段排序修改-------*/
ALTER PROCEDURE dbo.proc_ListPage
(
@tblName     nvarchar(200),        ----要显示的表或多个表的连接
@fldName     nvarchar(500) = '*',    ----要显示的字段列表
@pageSize    int = 1,        ----每页显示的记录个数
@page        int = 10,        ----要显示那一页的记录
@pageCount    int = 1 output,            ----查询结果分页后的总页数
@Counts    int = 1 output,                ----查询到的记录数
@fldSort    nvarchar(200) = null,    ----排序字段列表或条件
@Sort        bit = 0,        ----排序方法,0为升序,1为降序(如果是多字段排列Sort指代最后一个排序字段的排列顺序(最后一个排序字段不加排序标记)--程序传参如:' SortA Asc,SortB Desc,SortC ')
@strCondition    nvarchar(1000) = null,    ----查询条件,不需where
@ID        nvarchar(150),        ----主表的主键
@Dist                 bit = 0           ----是否添加查询字段的 DISTINCT 默认0不添加/1添加
)
AS
SET NOCOUNT ON
Declare @sqlTmp nvarchar(1000)        ----存放动态生成的SQL语句
Declare @strTmp nvarchar(1000)        ----存放取得查询结果总数的查询语句
Declare @strID     nvarchar(1000)        ----存放取得查询开头或结尾ID的查询语句Declare @strSortType nvarchar(10)    ----数据排序规则A
Declare @strFSortType nvarchar(10)    ----数据排序规则BDeclare @SqlSelect nvarchar(50)         ----对含有DISTINCT的查询进行SQL构造
Declare @SqlCounts nvarchar(50)          ----对含有DISTINCT的总数查询进行SQL构造
if @Dist  = 0
begin
    set @SqlSelect = 'select '
    set @SqlCounts = 'Count(*)'
end
else
begin
    set @SqlSelect = 'select distinct '
    set @SqlCounts = 'Count(DISTINCT '+@ID+')'
end
if @Sort=0
begin
    set @strFSortType=' ASC '
    set @strSortType=' DESC '
end
else
begin
    set @strFSortType=' DESC '
    set @strSortType=' ASC '
end--------生成查询语句--------
--此处@strTmp为取得查询结果数量的语句
if @strCondition is null or @strCondition=''     --没有设置显示条件
begin
    set @sqlTmp =  @fldName + ' From ' + @tblName
    set @strTmp = @SqlSelect+' @Counts='+@SqlCounts+' FROM '+@tblName
    set @strID = ' From ' + @tblName
end
else
begin
    set @sqlTmp = + @fldName + 'From ' + @tblName + ' where (1>0) ' + @strCondition
    set @strTmp = @SqlSelect+' @Counts='+@SqlCounts+' FROM '+@tblName + ' where (1>0) ' + @strCondition
    set @strID = ' From ' + @tblName + ' where (1>0) ' + @strCondition
end----取得查询结果总数量-----
exec sp_executesql @strTmp,N'@Counts int out ',@Counts out
declare @tmpCounts int
if @Counts = 0
    set @tmpCounts = 1
else
    set @tmpCounts = @Counts    --取得分页总数
    set @pageCount=(@tmpCounts+@pageSize-1)/@pageSize    /**//**当前页大于总页数 取最后一页**/
    if @page>@pageCount
        set @page=@pageCount    --/*-----数据分页2分处理-------*/
    declare @pageIndex int --总数/页大小
    declare @lastcount int --总数%页大小     set @pageIndex = @tmpCounts/@pageSize
    set @lastcount = @tmpCounts%@pageSize
    if @lastcount > 0
        set @pageIndex = @pageIndex + 1
    else
        set @lastcount = @pagesize    --//***显示分页
    if @strCondition is null or @strCondition=''     --没有设置显示条件
    begin
        if @pageIndex<2 or @page<=@pageIndex / 2 + @pageIndex % 2   --前半部分数据处理
            begin 
                set @strTmp=@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName
                        +' where '+@ID+' not in('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-1) as Varchar(20)) +' '+ @ID +' from '+@tblName
                        +' order by '+ @fldSort +' '+ @strFSortType+')'
                        +' order by '+ @fldSort +' '+ @strFSortType 
            end
        else
            begin
            set @page = @pageIndex-@page+1 --后半部分数据处理
                if @page <= 1 --最后一页数据显示
                    set @strTmp=@SqlSelect+' * from ('+@SqlSelect+' top '+ CAST(@lastcount as VARCHAR(4))+' '+ @fldName+' from '+@tblName
                        +' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType 
                else                
                    set @strTmp=@SqlSelect+' * from ('+@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName
                        +' where '+@ID+' not in('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-2)+@lastcount as Varchar(20)) +' '+ @ID +' from '+@tblName
                        +' order by '+ @fldSort +' '+ @strSortType+')'                        +' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType 
            end
    end    else --有查询条件
    begin
        if @pageIndex<2 or @page<=@pageIndex / 2 + @pageIndex % 2   --前半部分数据处理
        begin 
                set @strTmp=@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName +' from  '+@tblName
                    +' where '+@ID+' not in('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-1) as Varchar(20)) +' '+ @ID +' from '+@tblName
                    +' Where (1>0) ' + @strCondition + ' order by '+ @fldSort +' '+ @strFSortType+')'
                    +' ' + @strCondition + ' order by '+ @fldSort +' '+ @strFSortType                 
        end
        else
        begin 
            set @page = @pageIndex-@page+1 --后半部分数据处理
            if @page <= 1 --最后一页数据显示
                    set @strTmp=@SqlSelect+' * from ('+@SqlSelect+' top '+ CAST(@lastcount as VARCHAR(4))+' '+ @fldName+' from '+@tblName
                        +' where (1>0) '+ @strCondition +' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType
            else
                    set @strTmp=@SqlSelect+' * from ('+@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName
                        +' where '+@ID+' not in('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-2)+@lastcount as Varchar(20)) +' '+ @ID +' from '+@tblName
                        +' where (1>0) '+ @strCondition +' order by '+ @fldSort +' '+ @strSortType+')'
                        + @strCondition +' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType 
        end    
    end------返回查询结果-----
exec sp_executesql @strTmp
--print @strTmp
SET NOCOUNT OFF

解决方案 »

  1.   

    http://school.ywan.com/Program/net/479910.html
    这是个例子
      

  2.   

    .NET技术群12845737.
    大量学习资料下载.讨论VC/C#/ASP.NET/FLASH_AS技术欢迎学习和技术人员加入 
    探讨技术,分享程序员生活.
      

  3.   

    http://blog.csdn.net/jyk/archive/2007/03/01/1518354.aspx这里有简单的说就是select top 11 @id = ID from Table select top 10 * from Table where ID >= @ID (公式:PageSize * (PageIndex - 1) + 1 = 11)
    A 高效算法
    这是一个非常追求效率的算法,依据MSSQL的特性,为简单分页的情况量身定做的。
    第一个特性:select top 11 @id = ID from Table
    Top 和 给变量赋值都是很常用的方法,但是这种组合不太常见吧。这是我在一个偶然的情况下发现的,这么写有什么作用呢?先来看看@id会得到什么值。@id 得到的是最后一条记录的ID字段的值,前面的记录的值会被覆盖。
    假设分页要求是:每页显示10条记录,按照ID字段升序显示。那么这时候 select top 10 * from Table where ID >= @ID 得到的记录集就是第二页所需要的数据。第三页的数据只要把第一个语句 top 后面的 “11”改成“21”就可以了。公式:PageSize * (PageIndex - 1) + 1
    要想使用这个特性必须满足几个条件:排序字段只能有一个,排序字段的值不能有太多重复的,有重复值会造成分页不准,甚至无法翻到下一页的情况。所以这个算法只适用于“简单分页”的情况。不过好在一个网站里面有很多情况都是“简单分页”的情况,随意这个算法还是有价值的。
    Ps:这个特性好像只有MSSQL才有,SQLAnywhere是不容许这样写的,除非记录集只有一条记录,oracle 根本就没有top,其它的数据库没有研究过。
    思路:先定位(数数),后取记录集(ID >= 的方法)。
    优点:第一个语句只取一个字段,即使是top 10000也可以把占用的资源降到最低。如果排序字段有索引的话效果更佳。
     
    B 一般算法
    针对上面的算法的不足,可以采用这个算法,颠颠倒倒法,就是top嵌套。还有一个大名,忘记了(研究出算法后才发现的)。
    select [*] from [Table] where [ID] in (
        select top 10 [ID] from 
    (
             select top 20 [ID] ,AddedDate from [Table]
             order by [AddedDate] desc,[ID]
    ) as aa order by [AddedDate] ,[ID] desc
    )order by [AddedDate] desc,[ID]
     
    应该有似曾相识的感觉吧,这里呢也是随求了一下效率,并不是最最通用的算法。
    思路:先定位(数数),再取主键值,最后取记录集(ID in 的方法)。
    优点:中间“运算”部分只提取主键和排序字段,其他的字段一律不取,这样可以节省点内存。(缺点:只能是单一主键,不能是复合主键!)
     
    C 通用算法
    select top 10 [*] from 
    select top 10 [*] from 
    (
             select top 20 [*] from [Table]
             order by [AddedDate] desc,[ID]
    ) as aa order by [AddedDate] ,[ID] desc
    ) as aa order by [AddedDate] desc ,[ID] 
     
    复合主键的情况也可以了,不过最内部的select提取的是所有需要显示的字段,在翻到后面的页的时候效率就慢了。
     
      

  4.   

    晕 楼上 我的:)http://blog.csdn.net/hertcloud/category/281167.aspx通用的存储过程分页有调用说明
      

  5.   

    通用:
    ALTER          PROCEDURE proc_pageBar(@pageSize int,@curPage int,@fldName varchar(600),@tbName varchar(50),@condition varchar(1500))
    /*
    用于翻页取得记录内容以及记录数与总页数
    @pageSize页的大小
    @curPage当前页
    @fldName查询字段名
    @tbName要查询的表名
    @condition查询条件
    lyt:2004 exec eouf_getTempTB select * from ##temp
    exec proc_pageBar 15,1,'proNO,var_qyP11,proName,proNum','##temp','where var_qyP11=''1111111122'''
    */
     AS
    declare @strSQL nvarchar(800),@RecordCount int,@TempPageCount decimal(6,2),@PageCount int
    if exists(select * from tempdb..sysobjects where name='##page')
    drop table ##page
    --print '@condition='+@condition
    set @strSQL = 'select identity(int,1,1) as sID,'+@fldName+' into ##page from '+@tbName+'  '+@condition
    exec sp_executesql @strSQL
    set @RecordCount = @@RowCount --记录数
    set @TempPageCount = cast(@RecordCount as decimal(6,2))/@pageSize
    set @PageCount = ceiling(@TempPageCount)--页数
    select a.*,@RecordCount RecordCount,@PageCount PageCount from ##page a where sID between (@curPage-1)*@pageSize+1 and @curPage*@pageSize
      

  6.   


    同于对于 改成 特例 还是是很简单的..
    exec sp_executesql @strTmp
    --print @strTmp
    SET NOCOUNT OFF这里将print @strTmp打开
    看看里面的输出 将通用的地方换成特定的表 字段等 即可效率绝对没有问题 特别是主键在 int这样的类型下 使用top max这样的方式 相当的快
    当然最通用的还是not in了
    不过sql 2005 有了行记录 分页更简单
      

  7.   

    sqlserver2005中使用下面这个会更简单:
    -- =============================================
    -- Author: lyt
    -- Create date: 2007-03-22
    -- Description: 通过分页存储过程
    /*
     @vTable: 要查询的表
     @vFields: 要查询的字段 
     @@Vorder: 排序字段
     @vCondition: 查询条件
     @iStartIndex 当前页数据记录的起始索引
     @iPageSize : 每页显示的项数 调用示例
     exec PageInfo 'adminInfo_t','vAName','iAID','1=1',1,4
     exec PageInfo 'news_v','vTitle,''/StudyHtmlNews/'' + vFolderName + ''/'' + vHtmlFileName + ''.html'' AS HtmlUrl', 'iID', '1=1', 1, 2
    */
    -- =============================================
    ALTER PROCEDURE [dbo].[PageInfo] 
    @vTable nvarchar(100),@vFields nvarchar(max),@Vorder varchar(50),@vCondition nvarchar(max),@iStartIndex int,@iPageSize int
    AS
    BEGIN
    declare @sqlTxt nvarchar(max)
    set @sqlTxt='WITH OrderedOrders AS (SELECT '+@vFields+',ROW_NUMBER() OVER (ORDER BY '+@Vorder+' DESC) AS RowNumber FROM '+@vTable+' where '+@vCondition+') SELECT * FROM OrderedOrders WHERE RowNumber BETWEEN '+convert(varchar,@iStartIndex)+' AND '+convert(varchar,(@iStartIndex+@iPageSize-1))
    exec sp_executesql @sqlTxt 
    END
      

  8.   


    高效通用的分页存储过程是带有sql注入漏洞的 http://www.cnblogs.com/yukaizhao/archive/2007/03/09/pagination_proc_problem.html