可按任意字段排序的分页存储过程

简介: 最近做一个项目,其中有许多部分需要用到分页功能 并且这些需要分页的地方有一个共同的特点,那就是,分页,但并不是按ID(主键)来排序,而是要求按其他有重复值的列进行排序,比如,其中有一个页面,要列出将近1万条客户记录,要求按客户付费金额进行排序,这种情况,如果使用网上流行的通用分页存储过程是行不能的,...

最近做一个项目,其中有许多部分需要用到分页功能
并且这些需要分页的地方有一个共同的特点,那就是,分页,但并不是按ID(主键)来排序,而是要求按其他有重复值的列进行排序,比如,其中有一个页面,要列出将近1万条客户记录,要求按客户付费金额进行排序,这种情况,如果使用网上流行的通用分页存储过程是行不能的,比如,像下面的分页存储过程虽然很棒,可是,用在这里的话,就无计可施:(这个存储过程是我在CSDN上看到一位前辈高人写的)

img_a6339ee3e57d1d52bc7d02b338e15a60.gif CREATE   PROCEDURE  GetRecordFromPage
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    @tblName      
varchar ( 255 ),        --  表名
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    @fldName       varchar ( 255 ),        --  字段名
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    @PageSize      int   =   10 ,            --  页尺寸
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    @PageIndex     int   =   1 ,             --  页码
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    @IsCount       bit   =   0 ,             --  返回记录总数, 非 0 值则返回
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    @OrderType     bit   =   0 ,             --  设置排序类型, 非 0 值则降序
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    @strWhere      varchar ( 4000 =   ''    --  查询条件 (注意: 不要加 where)
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
AS
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
declare   @strSQL    varchar ( 6000 )      --  主语句
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
declare  @strTmp    varchar ( 6000 )      --  临时变量
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
declare  @strOrder  varchar ( 6000 )        --  排序类型
img_a6339ee3e57d1d52bc7d02b338e15a60.gif

img_a6339ee3e57d1d52bc7d02b338e15a60.gif
if  @OrderType  !=   0
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
begin
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @strTmp  =  " < ( select   min "
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @strOrder  =  "  order   by   [ " + @fldName +" ]   desc "
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
end
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
else
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
begin
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @strTmp  =  " > ( select   max "
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @strOrder  =  "  order   by   [ " + @fldName +" ]   asc "
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
end
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
set  @strSQL  =  " select   top  "  +   str (@PageSize)  +  "  *   from   [ "
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    + @tblName + "
]   where   [ " + @fldName + " ] +  @strTmp  +  "( [ "
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    + @fldName + "
] from  ( select   top  "  +   str ((@PageIndex - 1 ) * @PageSize)  +  "  [ "
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    + @fldName + "
]   from   [ " + @tblName + " ] +  @strOrder  +  ")  as  tblTmp)"
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
+  @strOrder
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
if  @strWhere  !=   ''
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @strSQL  =  " select   top  "  +   str (@PageSize)  +  "  *   from   [ "
img_a6339ee3e57d1d52bc7d02b338e15a60.gif        + @tblName + "
]   where   [ " + @fldName + " ] +  @strTmp  +  "( [ "
img_a6339ee3e57d1d52bc7d02b338e15a60.gif        + @fldName + "
] from  ( select   top  "  +   str ((@PageIndex - 1 ) * @PageSize)  +  "  [ "
img_a6339ee3e57d1d52bc7d02b338e15a60.gif        + @fldName + "
]   from   [ " + @tblName + " ]   where  ("  +  @strWhere  +  ") "
img_a6339ee3e57d1d52bc7d02b338e15a60.gif        
+  @strOrder  +  ")  as  tblTmp)  and  ("  +  @strWhere  +  ") "  +  @strOrder
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
if  @PageIndex  =   1
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
begin
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @strTmp  =  ""
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
if  @strWhere  !=   ''
img_a6339ee3e57d1d52bc7d02b338e15a60.gif        
set  @strTmp  =  "  where  ("  +  @strWhere  +  ")"
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @strSQL  =  " select   top  "  +   str (@PageSize)  +  "  *   from   [ "
img_a6339ee3e57d1d52bc7d02b338e15a60.gif        + @tblName + "
] +  @strTmp  +  " "  +  @strOrder
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
end
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
if  @IsCount  !=   0
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @strSQL  =  " select   count ( * as  Total  from   [ " + @tblName + " ] "
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
exec  (@strSQL)
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
GO
这个分页存储过程我一直用于某些场所,如果大家用过,相信应该比较认可它的性能,可是,从代码中,我们看到,它有一个基本的要求,即是表或视图必定有一个主键,隐含的要求是排序字段必须是一个具备唯一值的字段,这在我上面提到的应用是不可能满足的,所以,这个存储过程虽然有用,可是,在这个场合,却用不上
后来看到CNBLOGS上另一位仁兄谈到的关于ASP.NET FORUM使用的临时表分页法,就写了一个临时表的分页存储过程,也是通用的,实现起来比较上的方法还要容易,如下
img_a6339ee3e57d1d52bc7d02b338e15a60.gif CREATE   PROCEDURE  dbo.GetPageRecord
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    (
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    @tblName      
varchar ( 255 ),        --  表名
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    @fldlist  varchar ( 1000 ) = ' * ' ,
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    @fldName      
varchar ( 255 ),        -- 排序字段
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    @KeyField      varchar ( 255 ),         -- 主键
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    @PageSize      int   =   10 ,            --  页尺寸
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    @PageIndex     int   =   1 ,             --  页码
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    @IsCount       bit   =   0 ,             --  返回记录总数, 非 0 值则返回
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    @OrderType     bit   =   1 ,             --  设置排序类型, 非 0 值则降序
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    @strWhere      varchar ( 4000 =   ''    --  查询条件 (注意: 不要加 where)
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
AS
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
SET  NOCOUNT  ON
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
DECLARE  @PageLowerBound  int
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
DECLARE  @PageUpperBound  int
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
--  Set the page bounds
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
SET  @PageLowerBound  =  @PageSize  *  @PageIndex
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
SET  @PageUpperBound  =  @PageLowerBound  +  @PageSize  +   1
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
--  Create a temp table to store the select results
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
create   table  # temp
img_a6339ee3e57d1d52bc7d02b338e15a60.gif(
img_a6339ee3e57d1d52bc7d02b338e15a60.gif     RecNo 
int   IDENTITY  ( 1 1 NOT   NULL ,
img_a6339ee3e57d1d52bc7d02b338e15a60.gif     oldid 
int
img_a6339ee3e57d1d52bc7d02b338e15a60.gif)
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
-- generate record
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
Declare  @Sqlstr  varchar ( 6000 )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
set  @sqlstr = ' select  ' + @Keyfield + '  from  ' + @tblname
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
if (@strWhere <> '' )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
begin
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @Sqlstr = @sqlstr + '  where ( ' + @strWhere + ' ) '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
end
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
set  @sqlstr = @sqlstr + '  order by  ' + @fldName
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
if (@ordertype = 0 )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
begin
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + '  asc '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
end
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
else
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
begin
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + '  desc '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
end
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
set  @sqlstr = ' insert into #temp (oldid)  ' + @sqlstr
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
execute (@sqlstr)
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
set  @sqlstr = ' SELECT  ' + @fldList + '  FROM  ' + @tblname + '  TableA (nolock), #temp T WHERE T.oldid = TableA. ' + @keyfield + '  AND T.RecNo >  ' +   cast (@PageLowerBound  as   varchar ) + '  AND  T.RecNo <  ' + cast (@PageUpperBound  as   varchar ) + '  ORDER BY T.RecNo '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
execute (@sqlstr)
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
GO
使用了这个临时表方案的存储过程后,为了提高性能,我大约在上面耗费了将近四天,反复测试性能,后来发现,无论怎样的办法,由于临时表的性能的限制,就算将SELECT语句优化再优化,可是,还是由于临时表的建立与丢弃在读写磁盘上耗费太多时间而导致该存储过程稳定性极差.为什么呢.我做了个测试,一个人访问用此方法分页的WEB页面尚可,速度也理想(2000条记录),但是,当5人以上访问此页面时,IIS会因过重负荷而导致ASP工作进程与W3P进程通信失败,并且,SQL SERVER也会不定时出现缓冲区错误.为什么呢?我想,正是由于使用了临时表吧,后来,看到有人提议使用表变量,可是,想想,还是行不通,因为我的查询条件是动态传入的参数呀
由于性能差,导致我的WEB应用在处理分页时频频当机,于是下定决心重写新的存储过程
昨晚在家从七点到十二点一直在写,其实写分页存储过程的原理应该相当简单,下面的图反映出以下,我两种存储过程实现的不同思想
111.JPG
原理是很简单,大家都能想得到,问题是,过渡性结果集如何产生的问题,如果不是因为表名,条件,页码是参数化的化,我们大可以用一句SELECT TOP来完成它,可是,问题是,不能,因为它们是参数化的,下面的关键性内容将解除你这方面的顾虑,让我们一起来研究一下MS SQL SERVER中隐藏的秘密吧:
第一个秘密是关于SELECT语句的:
SQL中的SELECT语句可以将另外一个SELECT语句作为内容来源,并且按此规律进行嵌套处理,但是,有一个前提,必须对作为来源的SELEC结果集指定别名,下面是一个示例性SQL语句,你可以在查询分析器里证实它:
img_a6339ee3e57d1d52bc7d02b338e15a60.gif select   top   10   *   from  ( select   top   100   *   from  tblproducts  where  name  like   ' %mp3% '   order   by  id  desc as  a  order   by  id  desc
请相信你的眼睛,上面的语句确实能执行,可能你曾经试过执行类似的语句但并未成功,那是因为你没有将来源结果集指定别名
第二个秘密是一个规则:
如果你想用select top  20*4的方式在SQL中取前80条记录,你会失败,因为TOP子句有一个限制,就是TOP num中的num不能是一个计算值或表达式而必须是一个既定的常量
第三个秘密足够重大,我想,应该很少有人发现它,否则的话,很多问题便会变得简单起来,简要的说,它就是:SQL允许你用EXECUTE执行一个变量中定义的SQL语句,并且允许你在被执行的SQL语句中,再次嵌套入一个变量定义的语句,并且再次在其中用EXECUTE执行它,如果语言不足以证明,那么下面的代码将证明这是行得通并且是很好的
img_a6339ee3e57d1d52bc7d02b338e15a60.gif declare  @sqlstr  varchar ( 3000 )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
set  @sqlstr = ' declare @subsqlstr varchar(1000); '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
set  @sqlstr = @sqlstr + ' set @subsqlstr= '' select * from tblproducts '' ; '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
set  @sqlstr = @sqlstr + ' execute (@subsqlstr) '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
execute (@sqlstr)

在上面的代码中,@SQL变量中定义的是一组SQL语句,在这组SQL语句中,又定义了一个@SUBSQL变量,在其中存放了SELECT语句,
所以,当系统执行@SQLSTR时,其中定义的变量会被执行,执行的结果是,构造了一组动态执行的SQL语句,将其存入了变量,最后,在EXECUTE中又被执行,这种嵌套的执行,我们就姑且称其为动态执行能力吧
不过,需要相当注意的是:
1,由于在变量中存放语句组,因此,且莫忘记在每一个语句末尾加上分号(分号是SQL一句语句的结束标志)
2,如果在语句中包含变量的赋值,请记住你是在写一个变量赋值语句,因此记住加上单引号将值括起
3,如果你在变量中定义的语句组中要引用字符串常量,请先将单引号替换成两个单引号

最后,我用上面的方法写了两种SQL通用分页存储过程:
它们具有以下特点1,支持字段集合选择,2支持任意字段排序,
111.JPG
上面的图,我们以最终结果集倒序为例,第一种方案,我们先取集集合OB,这可以用一个使用SELECT TOP 并使用升级排列的语句完成
然后对OB结果集进行倒序排序,再用"SELECT TOP 每页记录数"倒序 的方式取得目标集合AB,下面是存储过程
img_a6339ee3e57d1d52bc7d02b338e15a60.gif create   PROCEDURE  dbo.GetPagingData
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    (
img_a6339ee3e57d1d52bc7d02b338e15a60.gif        @tablename 
varchar ( 100 ), -- 表名或视图表
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
        @fieldlist  varchar ( 4000 ) = ' * ' , -- 欲选择字段列表
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
        @orderfield  varchar ( 100 ), -- 排序字段
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
        @keyfield  varchar ( 100 ), -- 主键
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
        @pageindex  int , -- 页号,从0开始
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
        @pagesize  int = 20 , -- 页尺寸
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
        @strwhere  varchar ( 4000 ), -- 条件
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
        @ordertype  bit = 1 -- 排序,1,降序,0,升序
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
AS
img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif
/**/ /*
img_33d02437d135341f0800e3d415312ae8.gif名称:GetPagingRecord
img_33d02437d135341f0800e3d415312ae8.gif作用:按任意字段进行排序分页
img_33d02437d135341f0800e3d415312ae8.gif作者:菩提树(MARK MA)
img_33d02437d135341f0800e3d415312ae8.gif时间:2004-12-14
img_33d02437d135341f0800e3d415312ae8.gif声明:此代码你可以无偿使用及转载,但在转载时,请勿移称本文字声明
img_05dd8d549cff04457a6366b0a7c9352a.gif
*/

img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
SET  NOCOUNT  ON
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
declare  @sqlstr  varchar ( 6000 )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
-- 处理SQL中危险字符,并且将条件处理成易嵌入的形式    
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
     set  @sqlstr = ' declare @Rcount int; '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + ' set @rcount=(select count( ' + @keyfield + ' ) from  ' + @tablename + '  where  ' + @strWhere + ' ); '     
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @strwhere = replace (@strwhere, '''' , '''''' )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @strwhere = replace (@strwhere, ' -- ' , '' )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @strwhere = replace (@strwhere, ' ; ' , '' )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + ' declare @Rnum int; '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + ' set @rnum=@rcount- ' + cast (@pagesize  as   varchar ) + ' * ' + cast (@pageindex  as   varchar ) + ' ; '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + ' declare @sqlstr varchar(6000); '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
if  @ordertype = 1
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
begin
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + ' set @sqlstr= '' select top  ' + cast (@Pagesize  as   varchar ) + '   ' + @fieldlist + '  from (select top 100 
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gifpercent * from  (select top  
'' +cast(@rnum as varchar)+ ''  * from  ' + @tablename + '  where  ' + @strwhere + '  
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.giforder by 
' + @orderfield + '  asc) as b order by paymoney desc) as a order by  ' + @orderfield + '  desc  '' ; '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
end
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
else
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
begin
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + ' set @sqlstr= '' select top  ' + cast (@Pagesize  as   varchar ) + '   ' + @fieldlist + '  from (select top 100 
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gifpercent * from  (select top  
'' +cast(@rnum as varchar)+ ''  * from  ' + @tablename + '  where  ' + @strwhere + '  
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.giforder by 
' + @orderfield + '  desc) as b order by paymoney asc) as a order by  ' + @orderfield + '  asc  '' ; '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
end
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + ' if @Rcount>0 begin execute(@sqlstr) end '     
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
-- print @sqlstr
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
     execute (@sqlstr)

在上面的代码中,还处理了没有符合条件结果的情况
第二种方案的思想是这样的,先用倒序的SELECT TOP (页序号+1)*页尺寸的方法取得AE结果集,再从AE结果集中用NOT IN 的方法排除掉用SELECT TOP 页序号*页尺寸的方法取得的结果集,最后,对目标结果集执行倒序,下面是实现的代码
img_a6339ee3e57d1d52bc7d02b338e15a60.gif create   PROCEDURE  dbo.GetPagingRecord
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    (
img_a6339ee3e57d1d52bc7d02b338e15a60.gif        @tablename 
varchar ( 100 ), -- 表名或视图表
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
        @fieldlist  varchar ( 4000 ) = ' * ' , -- 欲选择字段列表
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
        @orderfield  varchar ( 100 ), -- 排序字段
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
        @keyfield  varchar ( 100 ), -- 主键
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
        @pageindex  int , -- 页号,从0开始
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
        @pagesize  int = 20 , -- 页尺寸
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
        @strwhere  varchar ( 4000 ), -- 条件
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
        @ordertype  bit = 1 -- 排序,1,降序,0,升序
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
    )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
AS
img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif
/**/ /*
img_33d02437d135341f0800e3d415312ae8.gif名称:GetPagingRecord
img_33d02437d135341f0800e3d415312ae8.gif作用:按任意字段进行排序分页
img_33d02437d135341f0800e3d415312ae8.gif作者:菩提树(MARK MA)
img_33d02437d135341f0800e3d415312ae8.gif时间:2004-12-14
img_33d02437d135341f0800e3d415312ae8.gif声明:此代码你可以无偿使用及转载,但在转载时,请勿移称本文字声明
img_05dd8d549cff04457a6366b0a7c9352a.gif
*/

img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
SET  NOCOUNT  ON
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
declare  @sqlstr  varchar ( 6000 )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
-- 处理SQL中危险字符,并且将条件处理成易嵌入的形式
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
     set  @strwhere = replace (@strwhere, '''' , '''''' )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @strwhere = replace (@strwhere, ' -- ' , '' )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @strwhere = replace (@strwhere, ' ; ' , '' )
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = ' declare @CurPageNum int; '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + ' declare @nextpagenum int; '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + ' set @curpagenum= ' + cast (@PageIndex  as   varchar ) + ' * ' + cast (@Pagesize  as   varchar ) + ' ; '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + ' set @nextpagenum= ' + cast (@PageIndex + 1   as   varchar ) + ' * ' + cast (@Pagesize  as   varchar ) + ' ; '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + ' declare @sqlstr varchar(6000); '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
if  @ordertype = 1
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
begin
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + ' set @sqlstr= '' select  ' + @fieldlist + '  from ( select top  '' +cast(@nextpagenum as varchar)+ ''  * from 
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
' + @tablename + '   where  ' + @strwhere + '  order by  ' + @orderfield + '  desc ) as a where  ' + @keyfield + '  not in ( 
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gifselect top 
'' +cast(@curpagenum as varchar)+ ''   ' + @keyfield + '  from  ' + @tablename + '  where  ' + @strwhere + '  
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.giforder by 
' + @orderfield + '  desc) order by  ' + @orderfield + '  desc '' ; '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
end
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
else
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
begin
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + ' set @sqlstr= '' select  ' + @fieldlist + '  from ( select top  '' +cast(@nextpagenum as varchar)+ ''  * from 
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
' + @tablename + '   where  ' + @strwhere + '  order by  ' + @orderfield + '  asc ) as a where  ' + @keyfield + '  not in ( 
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gifselect top 
'' +cast(@curpagenum as varchar)+ ''   ' + @keyfield + '  from  ' + @tablename + '  where  ' + @strwhere + '  
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.giforder by 
' + @orderfield + '  asc) order by  ' + @orderfield + '  asc '' ; '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
end
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
set  @sqlstr = @sqlstr + ' execute( @sqlstr) '
img_a6339ee3e57d1d52bc7d02b338e15a60.gif    
-- print @sqlstr
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
     execute (@sqlstr)

需要注意的是,如果要避免SQL注入式攻击,请注意处理像分号,双减号,单引号这些在SQL中有特殊含义的字符

至于上面两个存储过程哪个性能更好,那就取决于是对一个倒序的结果集再进入一次反序排列好呢,还是用NOT IN从一个大的结果集移除一个小的结果集好

希望对大家有帮助
如果需要转载,请标明出处,勿删减内容
目录
相关文章
|
1月前
|
SQL Oracle 关系型数据库
sql语句两个字段合并或者两个字段拼接显示
sql语句两个字段合并或者两个字段拼接显示
|
4月前
|
SQL
一条集多表查询、字段与字段拼接、合并每张表共同字段、新增列并赋值的SQL
一条集多表查询、字段与字段拼接、合并每张表共同字段、新增列并赋值的SQL
18 0
|
SQL Oracle 关系型数据库
Oracle简单查询、条件查询、枚举查询、模糊查询、排序查询、函数查询等
Oracle简单查询、条件查询、枚举查询、模糊查询、排序查询、函数查询等
223 0
Oracle简单查询、条件查询、枚举查询、模糊查询、排序查询、函数查询等
|
前端开发 数据库
FineReport中使用一个搜索框查询数据库中多列值返回一列值:使用union函数
前端使用一个查询框(搜索框)查询数据库中多列值,这里使用数据库的union函数进行实现
162 0
DataTable 修改列名 删除列 调整列顺序
DataTable 修改列名 删除列 调整列顺序
142 0
|
关系型数据库 MySQL 数据库
Mysql数据库,排序与单行处理函数篇
更复杂的情况,为多字段排序:🤡 比如我们想按照薪资升序排列,薪资一样的情况下,按照名字降序排序:
53 0
|
SQL 算法 关系型数据库
PostgreSQL 任意字段数组合 AND\OR 条件,指定返回结果条数,构造测试数据算法举例
标签 PostgreSQL , 构造测试数据 , 任意字段组合AND,OR查询 , 指定结果集大小 背景 在进行一些实际的POC测试时,需要根据业务提出的需求构造数据,比如按照任意字段数组合 AND\OR 条件,指定返回结果条数,构造测试数据。
1392 0