快精灵印艺坊 您身边的文印专家
广州名片 深圳名片 会员卡 贵宾卡 印刷 设计教程
产品展示 在线订购 会员中心 产品模板 设计指南 在线编辑
 首页 名片设计   CorelDRAW   Illustrator   AuotoCAD   Painter   其他软件   Photoshop   Fireworks   Flash  

 » 彩色名片
 » PVC卡
 » 彩色磁性卡
 » 彩页/画册
 » 个性印务
 » 彩色不干胶
 » 明信片
   » 明信片
   » 彩色书签
   » 门挂
 » 其他产品与服务
   » 创业锦囊
   » 办公用品
     » 信封、信纸
     » 便签纸、斜面纸砖
     » 无碳复印纸
   » 海报
   » 大篇幅印刷
     » KT板
     » 海报
     » 横幅

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


第一个秘密是关于SELECT语句的:
SQL中的SELECT语句可以将另外一个SELECT语句作为内容来源,并且按此规律进行嵌套处理,但是,有一个前提,必须对作为来源的SELEC结果集指定别名,下面是一个示例性SQL语句,你可以在查询分析器里证明它:
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执行它,假如语言不足以证实,那么下面的代码将证实这是行得通并且是很好的
declare @sqlstr varchar(3000)
set @sqlstr=\\\'\\\'declare @subsqlstr varchar(1000);\\\'\\\'
set @sqlstr=@sqlstr+\\\'\\\'set @subsqlstr=\\\'\\\'\\\'\\\'select * from tblproducts\\\'\\\'\\\'\\\';\\\'\\\'
set @sqlstr=@sqlstr+\\\'\\\'execute (@subsqlstr)\\\'\\\'
execute(@sqlstr)
在上面的代码中,@SQL变量中定义的是一组SQL语句,在这组SQL语句中,又定义了一个@SUBSQL变量,在其中存放了SELECT语句,
所以,当系统执行@SQLSTR时,其中定义的变量会被执行,执行的结果是,构造了一组动态执行的SQL语句,将其存入了变量,最后,在EXECUTE中又被执行,这种嵌套的执行,我们就姑且称其为动态执行能力吧
不过,需要相称注重的是:
1,由于在变量中存放语句组,因此,且莫忘记在每一个语句末尾加上分号(分号是SQL一句语句的结束标志)
2,假如在语句中包含变量的赋值,请记住你是在写一个变量赋值语句,因此记住加上单引号将值括起
3,假如你在变量中定义的语句组中要引用字符串常量,请先将单引号替换成两个单引号

最后,我用上面的方式写了两种SQL通用分页存储过程:
它们具有以下特点1,支持字段集合选择,2支持任意字段排序,
 
上面的图,我们以最终结果集倒序为例,第一种方案,我们先取集集合OB,这可以用一个使用SELECT TOP 并使用升级排列的语句完成
然后对OB结果集进行倒序排序,再用\"SELECT TOP 每页记录数\"倒序 的方法取得目标集合AB,下面是存储过程
create PROCEDURE dbo.GetPagingData
    (
        @tablename varchar(100),--表名或视图表
        @fieldlist varchar(4000)=\\\'\\\'*\\\'\\\',--欲选择字段列表
        @orderfield varchar(100),--排序字段
        @keyfield varchar(100),--主键
        @pageindex int,--页号,从0开始
        @pagesize int=20,--页尺寸
        @strwhere varchar(4000),--条件
        @ordertype bit=1--排序,1,降序,0,升序
    )
AS
/**//*
名称:GetPagingRecord
作用:按任意字段进行排序分页
作者:菩提树(MARK MA)
时间:2004-12-14
声明:此代码你可以无偿使用及转载,但在转载时,请勿移称本文字声明
*/
    SET NOCOUNT ON
    declare @sqlstr varchar(6000)
    --处理SQL中危险字符,并且将条件处理成易嵌入的形式    
    set @sqlstr=\\\'\\\'declare @Rcount int;\\\'\\\'
    set @sqlstr=@sqlstr+\\\'\\\'set @rcount=(select count(\\\'\\\'+@keyfield+\\\'\\\') from \\\'\\\'+@tablename+\\\'\\\' where \\\'\\\'+@strWhere+\\\'\\\');\\\'\\\'    
    set @strwhere=replace(@strwhere,\\\'\\\'\\\'\\\'\\\'\\\'\\\'\\\',\\\'\\\'\\\'\\\'\\\'\\\'\\\'\\\'\\\'\\\'\\\'\\\')
    set @strwhere=replace(@strwhere,\\\'\\\'--\\\'\\\',\\\'\\\'\\\'\\\')
    set @strwhere=replace(@strwhere,\\\'\\\';\\\'\\\',\\\'\\\'\\\'\\\')
    set @sqlstr=@sqlstr+\\\'\\\'declare @Rnum int;\\\'\\\'
    set @sqlstr=@sqlstr+\\\'\\\'set @rnum=@rcount-\\\'\\\'+cast(@pagesize as varchar)+\\\'\\\'*\\\'\\\'+cast(@pageindex as varchar)+\\\'\\\';\\\'\\\'
    set @sqlstr=@sqlstr+\\\'\\\'declare @sqlstr varchar(6000);\\\'\\\'
    if @ordertype=1
    begin
    set @sqlstr=@sqlstr+\\\'\\\'set @sqlstr=\\\'\\\'\\\'\\\'select top \\\'\\\'+cast(@Pagesize as varchar)+\\\'\\\' \\\'\\\'+@fieldlist+\\\'\\\' from (select top 100 
 
percent * from  (select top  \\\'\\\'\\\'\\\'+cast(@rnum as varchar)+\\\'\\\'\\\'\\\' * from \\\'\\\'+@tablename+\\\'\\\' where \\\'\\\'+@strwhere+\\\'\\\' 
 
order by \\\'\\\'+@orderfield+\\\'\\\' asc) as b order by paymoney desc) as a order by \\\'\\\'+@orderfield+\\\'\\\' desc \\\'\\\'\\\'\\\';\\\'\\\'
    end
    else
    begin
    set @sqlstr=@sqlstr+\\\'\\\'set @sqlstr=\\\'\\\'\\\'\\\'select top \\\'\\\'+cast(@Pagesize as varchar)+\\\'\\\' \\\'\\\'+@fieldlist+\\\'\\\' from (select top 100 
 
percent * from  (select top  \\\'\\\'\\\'\\\'+cast(@rnum as varchar)+\\\'\\\'\\\'\\\' * from \\\'\\\'+@tablename+\\\'\\\' where \\\'\\\'+@strwhere+\\\'\\\' 
 
order by \\\'\\\'+@orderfield+\\\'\\\' desc) as b order by paymoney asc) as a order by \\\'\\\'+@orderfield+\\\'\\\' asc \\\'\\\'\\\'\\\';\\\'\\\'
    end
    set @sqlstr=@sqlstr+\\\'\\\'if @Rcount>0 begin execute(@sqlstr) end\\\'\\\'    
    --print @sqlstr
    execute(@sqlstr)
在上面的代码中,还处理了没有符合条件结果的情况
第二种方案的思想是这样的,先用倒序的SELECT TOP (页序号+1)*页尺寸的方式取得AE结果集,再从AE结果集中用NOT IN 的方式排除掉用SELECT TOP 页序号*页尺寸的方式取得的结果集,最后,对目标结果集执行倒序,下面是实现的代码
create PROCEDURE dbo.GetPagingRecord
    (
        @tablename varchar(100),--表名或视图表
        @fieldlist varchar(4000)=\\\'\\\'*\\\'\\\',--欲选择字段列表
        @orderfield varchar(100),--排序字段
        @keyfield varchar(100),--主键
        @pageindex int,--页号,从0开始
        @pagesize int=20,--页尺寸
        @strwhere varchar(4000),--条件
        @ordertype bit=1--排序,1,降序,0,升序
    )
AS
/**//*
名称:GetPagingRecord
作用:按任意字段进行排序分页
作者:菩提树(MARK MA)
时间:2004-12-14
声明:此代码你可以无偿使用及转载,但在转载时,请勿移称本文字声明
*/
    SET NOCOUNT ON
    declare @sqlstr varchar(6000)
    --处理SQL中危险字符,并且将条件处理成易嵌入的形式
    set @strwhere=replace(@strwhere,\\\'\\\'\\\'\\\'\\\'\\\'\\\'\\\',\\\'\\\'\\\'\\\'\\\'\\\'\\\'\\\'\\\'\\\'\\\'\\\')
    set @strwhere=replace(@strwhere,\\\'\\\'--\\\'\\\',\\\'\\\'\\\'\\\')
    set @strwhere=replace(@strwhere,\\\'\\\';\\\'\\\',\\\'\\\'\\\'\\\')
    set @sqlstr=\\\'\\\'declare @CurPageNum int;\\\'\\\'
    set @sqlstr=@sqlstr+\\\'\\\'declare @nextpagenum int;\\\'\\\'
    set @sqlstr=@sqlstr+\\\'\\\'set @curpagenum=\\\'\\\'+cast(@PageIndex as varchar)+\\\'\\\'*\\\'\\\'+cast(@Pagesize as varchar)+\\\'\\\';\\\'\\\'
    set @sqlstr=@sqlstr+\\\'\\\'set @nextpagenum=\\\'\\\'+cast(@PageIndex+1 as varchar)+\\\'\\\'*\\\'\\\'+cast(@Pagesize as varchar)+\\\'\\\';\\\'\\\'
    set @sqlstr=@sqlstr+\\\'\\\'declare @sqlstr varchar(6000);\\\'\\\'
    if @ordertype=1
    begin
    set @sqlstr=@sqlstr+\\\'\\\'set @sqlstr=\\\'\\\'\\\'\\\'select \\\'\\\'+@fieldlist+\\\'\\\' from ( select top \\\'\\\'\\\'\\\'+cast(@nextpagenum as varchar)+\\\'\\\'\\\'\\\' * from 
 
\\\'\\\'+@tablename+\\\'\\\'  where \\\'\\\'+@strwhere+\\\'\\\' order by \\\'\\\'+@orderfield+\\\'\\\' desc ) as a where \\\'\\\'+@keyfield+\\\'\\\' not in ( 
 
select top \\\'\\\'\\\'\\\'+cast(@curpagenum as varchar)+\\\'\\\'\\\'\\\' \\\'\\\'+@keyfield+\\\'\\\' from \\\'\\\'+@tablename+\\\'\\\' where \\\'\\\'+@strwhere+\\\'\\\' 
 
order by \\\'\\\'+@orderfield+\\\'\\\' desc) order by \\\'\\\'+@orderfield+\\\'\\\' desc\\\'\\\'\\\'\\\';\\\'\\\'
    end
    else
    begin
    set @sqlstr=@sqlstr+\\\'\\\'set @sqlstr=\\\'\\\'\\\'\\\'select \\\'\\\'+@fieldlist+\\\'\\\' from ( select top \\\'\\\'\\\'\\\'+cast(@nextpagenum as varchar)+\\\'\\\'\\\'\\\' * from 
 
\\\'\\\'+@tablename+\\\'\\\'  where \\\'\\\'+@strwhere+\\\'\\\' order by \\\'\\\'+@orderfield+\\\'\\\' asc ) as a where \\\'\\\'+@keyfield+\\\'\\\' not in ( 
 
select top \\\'\\\'\\\'\\\'+cast(@curpagenum as varchar)+\\\'\\\'\\\'\\\' \\\'\\\'+@keyfield+\\\'\\\' from \\\'\\\'+@tablename+\\\'\\\' where \\\'\\\'+@strwhere+\\\'\\\' 
 
order by \\\'\\\'+@orderfield+\\\'\\\' asc) order by \\\'\\\'+@orderfield+\\\'\\\' asc\\\'\\\'\\\'\\\';\\\'\\\'
    end
    set @sqlstr=@sqlstr+\\\'\\\'execute( @sqlstr)\\\'\\\'
    --print @sqlstr
    execute(@sqlstr)
需要注重的是,假如要避免SQL注入式攻击,请注重处理像分号,双减号,单引号这些在SQL中有特别含义的字符

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


返回类别: 教程
上一教程: 升级SQL SERVER6.5到2000的注重事项
下一教程: 深入SQL SERVER 2000的内存治理机制(三)

您可以阅读与"可按任意字段排序的分页存储过程"相关的教程:
· 出色的近乎完美的分页存储过程
· SQL SERVER 存储过程的分页
· SQL SERVER平台用存储过程进行分页的两种方式
· 分页SQL SERVER存储过程
· 一个高效的数据分页的存储过程 可以轻松应付百万数据
    微笑服务 优质保证 索取样品