在论坛上看到的一个分页存储过程

CREATE   Proc   pager
@Source   nvarchar(4000),   --表名、视图名、查询语句
@Size   int=10,       --每页的大小(行数)
@Index   int=1,       --要显示的页
@List   nvarchar   (4000)= ' ',   --要显示的字段列表,如果查询结果有标识字段,需要指定此值,且不包含标识字段
@Order   nvarchar   (1000)= ' ',   --排序字段列表
@Count   int   =   null   output             --   输出记录数,   如果@Count为null,   则输出记录数,   否则不要输出
as
set   nocount   on
declare   @FdName   nvarchar(250)   --表中的主键或表、临时表中的标识列名
  ,@Id1   varchar(20),@Id2   varchar(20)   --开始和结束的记录号
  ,@Obj_ID   int         --对象ID
--表中有复合主键的处理
declare   @strfd   nvarchar(2000)   --复合主键列表
  ,@strjoin   nvarchar(4000)   --连接字段
  ,@strwhere   nvarchar(2000)   --查询条件


select   @Obj_ID=object_id(@Source)
  ,@List=case   isnull(@List, ' ')   when   ' '   then   '   * '   else   '   '+@List   end
  ,@Order=case   isnull(@Order, ' ')   when   ' '   then   ' '   else   '   order   by   '+@Order   end
  ,@Source=case   when   @Obj_ID   is   not   null   then   '   '+@Source   else   '   ( '+@Source+ ')   a '   end

--如果显示第一页,可以直接用top来完成
if   @Index=1  
begin
  if   @Count   is   null
begin
declare   @lbtop1   nvarchar(1000)
set   @lbtop1   =   'select   @Count   =   count(*)   from   '+@Source
exec   sp_executesql   @lbtop1,   N '@Count   int   out ',   @Count   out
end
  select   @Id1=cast(@Size   as   varchar(20))
  exec( 'select   top   '+@Id1+@List+ '   from   '+@Source+@Order)
  return
end

--如果是表,则检查表中是否有标识更或主键
if   @Obj_ID   is   not   null   and   objectproperty(@Obj_ID, 'IsTable ')=1
begin
  select   @Id1=cast(@Size   as   varchar(20))
    ,@Id2=cast((@Index-1)*@Size   as   varchar(20))

  select   @FdName=name   from   syscolumns   where   id=@Obj_ID   and   status=0x80
  if   @@rowcount=0       --如果表中无标识列,则检查表中是否有主键
  begin
    if   not   exists(select   1   from   sysobjects   where   parent_obj=@Obj_ID   and   xtype= 'PK ')
      goto   lbusetemp     --如果表中无主键,则用临时表处理

    select   @FdName=name   from   syscolumns   where   id=@Obj_ID   and   colid   in(
      select   colid   from   sysindexkeys   where   @Obj_ID=id   and   indid   in(
        select   indid   from   sysindexes   where   @Obj_ID=id   and   name   in(
          select   name   from   sysobjects   where   xtype= 'PK '   and   parent_obj=@Obj_ID
      )))
    if   @@rowcount> 1     --检查表中的主键是否为复合主键
    begin
      select   @strfd= ' ',@strjoin= ' ',@strwhere= ' '
      select   @strfd=@strfd+ ',[ '+name+ '] '
        ,@strjoin=@strjoin+ '   and   a.[ '+name+ ']=b.[ '+name+ '] '
        ,@strwhere=@strwhere+ '   and   b.[ '+name+ ']   is   null '
        from   syscolumns   where   id=@Obj_ID   and   colid   in(
        select   colid   from   sysindexkeys   where   @Obj_ID=id   and   indid   in(
          select   indid   from   sysindexes   where   @Obj_ID=id   and   name   in(
            select   name   from   sysobjects   where   xtype= 'PK '   and   parent_obj=@Obj_ID
        )))
      select   @strfd=substring(@strfd,2,2000)
        ,@strjoin=substring(@strjoin,5,4000)
        ,@strwhere=substring(@strwhere,5,4000)
      goto   lbusepk
    end
  end
end
else
  goto   lbusetemp

/*--使用标识列或主键为单一字段的处理方法--*/
lbuseidentity:  
if   @Count   is   null
begin
declare   @lbuseidentity   nvarchar(1000)
set   @lbuseidentity   =   'select   @Count   =   count(*)   from   '+@Source
exec   sp_executesql   @lbuseidentity,   N '@Count   int   out ',   @Count   out
end
  exec( 'select   top   '+@Id1+@List+ '   from   '+@Source
    + '   where   '+@FdName+ '   not   in(select   top   '
    +@Id2+ '   '+@FdName+ '   from   '+@Source+@Order
    + ') '+@Order
    )
  return

/*--表中有复合主键的处理方法--*/
lbusepk:    
if   @Count   is   null
begin
declare   @lbusepk   nvarchar(1000)
set   @lbusepk   =   'select   @Count   =   count(*)   from   '+@Source
exec   sp_executesql   @lbusepk,   N '@Count   int   out ',   @Count   out
end

  exec( 'select   '+@List+ '   from(select   top   '+@Id1+ '   a.*   from
    (select   top   100   percent   *   from   '+@Source+@Order+ ')   a
    left   join   (select   top   '+@Id2+ '   '+@strfd+ '  
    from   '+@Source+@Order+ ')   b   on   '+@strjoin+ '
    where   '+@strwhere+ ')   a '
    )
  return

/*--用临时表处理的方法--*/
lbusetemp:    
select   @FdName= '[ID_ '+cast(newid()   as   varchar(40))+ '] '
  ,@Id1=cast(@Size*(@Index-1)   as   varchar(20))
  ,@Id2=cast(@Size*@Index-1   as   varchar(20))

declare   @lbusetemp   nvarchar(4000)
set   @lbusetemp   =   'select   '+@FdName+ '=identity(int,0,1), '+@List+ '
    into   #tb   from '+@Source+@Order
+case   when   @Count   is   null   then   '   set   @Count   =   @@rowcount   '   else   ' '   end   +   '
  select   '+@List+ '   from   #tb   where   '+@FdName+ '   between   '
  +@Id1+ '   and   '+@Id2
  exec   sp_executesql   @lbusetemp,     N '@Count   int   out ',   @Count   out

GO

posted @ 2008-12-12 15:27  jay-c  阅读(107)  评论(0)    收藏  举报