好久没有上来写点东西了,今天正好有空,共享一些个人心得,就是关于分页的存储过程,这个问题应该是老生重谈了,网上的通用存储过程的类型已经够多了,但是,好象看到的基本上不能够满足一些复杂的sql语句的分页(也可能是我不够见多识广啊,呵呵),比如下面这句:
select''asCheckBox,A.TargetID,A.TargetPeriod,Convert(varchar(10),B.BeginDate,120)asBeginDate,
Convert(varchar(10),B.EndDate,120)asEndDate,C.SalesCode,C.SalesName,D.CatalogCode,D.CatalogName,
E.OrgID,E.OrgName,F.OrgIDasBranchOrgID,F.OrgCodeasBranchOrgCode,F.OrgNameasBranchOrgName,
A.Amount,''asDetailButton
fromChlSalesTargetasA
leftouterjoinChlSalesTargetPeriodasBonA.TargetPeriod=B.TargetPeriod
leftouterjoinChlSalesasConA.Sales=C.SalesCode
leftouterjoinChlItemCatalogasDonA.ItemCatalog=D.CatalogCode
leftouterjoinChlOrgaSEOnA.OrgID=E.OrgID
leftouterjoinChlOrgasFonC.BranchOrgID=F.OrgID
whereA.TargetPeriod>='200607'andA.TargetPeriod<='200608'andF.OrgCodelike'%123%'andE.OrgCodelike'%123%'
orderbyA.TargetPerioddesc,D.CatalogName上面这句sql里面有一些特殊情况,比如使用了Convert函数,而且没有主键,有多表连接,有表别名,字段别名等等,这些情况处理起来可能比较棘手,当然,其中的“''asCheckBox”是我系统当中的特例情况,用来做一些处理的。
我这里提供一个自己开发的通用分页存储过程,有什么好的建议和意见,大家请不吝指教。代码如下:
通用分页存储过程----Sp_Paging
///
============================================================
功能:通用分页存储过程
参数:
@PKvarchar(50),主键,用来排序的单一字段,空的话,表示没有主键,存储过程将自动创建标识列主键
@Fieldsvarchar(500),要显示的字段列表(格式如:ID,Code,Name)
@Tablesvarchar(1000),要使用的表集合(Org)
@Wherevarchar(500),查询条件(Codelike'100')
@OrderByvarchar(100),排序条件(支持多个排序字段,如:ID,Codedesc,Namedesc)
@PageIndexint,当前要显示的页的页索引,索引从1开始,无记录时为0。
@PageSizeint,页大小
创建者:HollisYao
创建日期:2006-08-06
备注:
============================================================
/
CreatePROCEDURE[dbo].[Sp_Paging]
@PKvarchar(50)='',
@Fieldsvarchar(500),
@Tablesvarchar(1000),
@Wherevarchar(500)='',
@OrderByvarchar(100),
@PageIndexint,
@PageSizeint
AS
--替换单引号,避免构造sql出错
set@Fields=replace(@Fields,'''','''''') --要执行的sql,切分为几个字符串,避免出现长度超过4k时的问题
declare@sql1varchar(4000)
declare@sql2varchar(4000) set@sql1=''
set@sql2=''
if@Whereisnotnullandlen(ltrim(rtrim(@Where)))>0
set@Where='where'+@Where
else
set@Where='where1=1' set@sql1=@sql1+'declare@TotalCountint'--声明一个变量,总记录数
set@sql1=@sql1+'declare@PageCountint'--声明一个变量,总页数
set@sql1=@sql1+'declare@PageIndexint'--声明一个变量,页索引
set@sql1=@sql1+'declare@StartRowint'--声明一个变量,当前页第一条记录的索引 set@sql1=@sql1+'select@TotalCount=count()from'+@Tables+@Where--获取总记录数
set@sql1=@sql1+'if@PageCount<=0begin'--如果记录数为0,直接输出空的结果集
set@sql1=@sql1+'select'+@Fields+'from'+@Tables+'where1<>1'
set@sql1=@sql1+'select0asPageIndex,0asPageCount,'+convert(varchar,@PageSize)+'asPageSize,0asTotalCount'
set@sql1=@sql1+'returnend' set@sql1=@sql1+'set@PageCount=(@TotalCount+'+convert(varchar,@PageSize)+'-1)/'+convert(varchar,@PageSize)--获取总页数
set@sql1=@sql1+'set@PageIndex='+convert(varchar,@PageIndex)--设置正确的页索引
set@sql1=@sql1+'if@PageIndex<0set@PageIndex=1'
set@sql1=@sql1+'if@PageIndex>@PageCountand@PageCount>0set@PageIndex=@PageCount'
set@sql1=@sql1+'set@StartRow=(@PageIndex-1)'+convert(varchar,@PageSize)+'+1' if(charindex(',',@OrderBy)=0andcharindex(@PK,@OrderBy)>0)
begin
--**
--****不需要创建主键****
--****
declare@SortDirectionvarchar(10)--排序方向,>=:升序,<=:倒序
set@SortDirection='>='
ifcharindex('desc',@OrderBy)>0
set@SortDirection='<='
set@sql2=@sql2+'declare@Sortvarchar(100)'--声明一个变量,用来记录当前页第一条记录的排序字段值
set@sql2=@sql2+'setrowcount@StartRow'--设置返回记录数截止到当前页的第一条
set@sql2=@sql2+'select@Sort='+@PK+'from'+@Tables+@Where+'orderby'+@OrderBy--获取当前页第一个排序字段值
set@sql2=@sql2+'setrowcount'+convert(varchar,@PageSize)--设置返回记录数为页大小
set@Where=@Where+'and'+@PK+@SortDirection+'@Sort'
set@sql2=@sql2+'select'+@Fields+'from'+@Tables+@Where+'orderby'+@OrderBy--输出最终显示结果
end
else
begin
--****
--*需要创建自增长主键**
--****
set@sql2=@sql2+'declare@EndRowint'
set@sql2=@sql2+'set@EndRow=@PageIndex*'+convert(varchar,@PageSize)
set@sql2=@sql2+'setrowcount@EndRow'
set@sql2=@sql2+'declare@PKBeginint'--声明一个变量,开始索引
set@sql2=@sql2+'declare@PKEndint'--声明一个变量,结束索引
set@sql2=@sql2+'set@PKBegin=@StartRow'
set@sql2=@sql2+'set@PKEnd=@EndRow'
--****
--****对特殊字段进行转换,以便可以插入到临时表**
--****
declare@TempFieldsvarchar(500)
set@TempFields=@Fields
set@TempFields=replace(@TempFields,'''''asCheckBox','')
set@TempFields=replace(@TempFields,'''''asDetailButton','''''asRadio','')
set@TempFields=LTRIM(RTRIM(@TempFields))
ifleft(@TempFields,1)=','--去除最左边的逗号
set@TempFields=substring(@TempFields,2,len(@TempFields))
ifright(@TempFields,'--去除最右边的逗号
set@TempFields=substring(@TempFields,1,len(@TempFields)-1) set@sql2=@sql2+'selectidentity(int,1)asPK,'+@TempFields+'into#tbfrom'+@Tables+@Where+'orderby'+@OrderBy
--****
--****去除字段的表名前缀,当有字段有别名时,只保留字段别名*
--**
declare@TotalFieldsvarchar(500)
declare@tmpvarchar(50)
declare@iint
declare@jint
declare@iLeftint--左括号的个数
declare@iRightint--右括号的个数
set@i=0
set@j=0
set@iLeft=0
set@iRight=0
set@tmp=''
set@TotalFields='' while(len(@Fields)>0)
begin
set@i=charindex(',@Fields) --去除字段的表名前缀
if(@i=0)
begin
--找不到逗号分割,即表示只剩下最后一个字段
set@tmp=@Fields
end
else
begin
set@tmp=substring(@Fields,@i)
end
set@j=charindex('.',@tmp)
if(@j>0)
set@tmp=substring(@tmp,@j+1,len(@tmp))
--*当有字段有别名时,只保留字段别名***** --带括号的情况要单独处理,如Convert(varchar(10),120)asEndDate
while(charindex('(',@tmp)>0)
begin
set@iLeft=@iLeft+1
set@tmp=substring(@tmp,charindex('(',@tmp)+1,Len(@tmp))
end
while(charindex(')',@tmp)>0)
begin
set@iRight=@iRight+1
set@tmp=substring(@tmp,charindex(')',Len(@tmp))
end --当括号恰好组队的时候,才能进行字段别名的处理
if(@iLeft=@iRight)
begin
set@iLeft=0
set@iRight=0
--不对这几个特殊字段作处理:CheckBox、DetailButton、Radio
if(charindex('CheckBox',@tmp)=0andcharindex('DetailButton',@tmp)=0andcharindex('Radio',@tmp)=0)
begin
--判断是否有别名
if(charindex('as',@tmp)>0)--别名的第一种写法,带'as'的格式
begin
set@tmp=substring(@tmp,charindex('as',@tmp)+2,len(@tmp))
end
else
begin
if(charindex('',@tmp)>0)--别名的第二种写法,带空格("")的格式
begin
while(charindex('',@tmp)>0)
begin
set@tmp=substring(@tmp,charindex('',len(@tmp))
end
end
end
end
set@TotalFields=@TotalFields+@tmp
end
if(@i=0)
set@Fields=''
else
set@Fields=substring(@Fields,@i+1,len(@Fields)) end
--print@TotalFields set@sql2=@sql2+'select'+@TotalFields+'from#tbwherePKbetween@PKBeginand@PKEndorderbyPK'--输出最终显示结果
set@sql2=@sql2+'droptable#tb'
end --输出“PageIndex(页索引)、PageCount(页数)、PageSize(页大小)、TotalCount(总记录数)”
set@sql2=@sql2+'select@PageIndexasPageIndex,@PageCountasPageCount,'
+convert(varchar,@TotalCountasTotalCount' --print@sql1+@sql2
exec(@sql1+@sql2)
如果使用这个通用分页存储过程的话,那么调用方法如下:
使用通用分页存储过程进行分页
/*//
============================================================
功能:获取销售目标,根据条件
参数:
@UserTypeint,
@OrgIDvarchar(500),
@TargetPeriodBeginnvarchar(50),
@TargetPeriodEndnvarchar(50),
@BranchOrgCodenvarchar(50),
@BranchOrgNamenvarchar(50),
@OrgCodenvarchar(50),
@OrgNamenvarchar(50),
@SalesCodenvarchar(50),
@SalesNamenvarchar(50),
@CatalogCodenvarchar(50),
@CatalogNamenvarchar(50),页大小
创建者:HollisYao
创建日期:2006-08-11
备注:
============================================================
*/
CreatePROCEDURE[dbo].[GetSalesTargetList]
@UserTypeint,
@OrgIDnvarchar(500),
@PageSizeint
AS
declare@Conditionnvarchar(2000)
set@Condition=''
if(@UserType<>1)
set@Condition=@Condition+'andA.OrgIDin('+@OrgID+')'
if(len(@TargetPeriodBegin)>0)
set@Condition=@Condition+'andA.TargetPeriod>='''+@TargetPeriodBegin+''''
if(len(@TargetPeriodEnd)>0)
set@Condition=@Condition+'andA.TargetPeriod<='''+@TargetPeriodEnd+''''
if(len(@BranchOrgCode)>0)
set@Condition=@Condition+'andF.OrgCodelike''%'+@BranchOrgCode+'%'''
if(len(@BranchOrgName)>0)
set@Condition=@Condition+'andF.OrgNamelike''%'+@BranchOrgName+'%'''
if(len(@OrgCode)>0)
set@Condition=@Condition+'andE.OrgCodelike''%'+@OrgCode+'%'''
if(len(@OrgName)>0)
set@Condition=@Condition+'andE.OrgNamelike''%'+@OrgName+'%'''
if(len(@SalesCode)>0)
set@Condition=@Condition+'andC.SalesCodelike''%'+@SalesCode+'%'''
if(len(@SalesName)>0)
set@Condition=@Condition+'andC.SalesNamelike''%'+@SalesName+'%'''
if(len(@CatalogCode)>0)
set@Condition=@Condition+'andD.CatalogCodelike''%'+@CatalogCode+'%'''
if(len(@CatalogName)>0)
set@Condition=@Condition+'andD.CatalogNamelike''%'+@CatalogName+'%'''
if(len(@Condition)>0)
set@Condition=substring(@Condition,5,len(@Condition))
--print@Condition
execsp_Paging
N'',N'''asCheckBox,
C.SalesCode,E.OrgID,A.Amount,''asDetailButton',
N'ChlSalesTargetasA
leftouterjoinChlSalesTargetPeriodasBonA.TargetPeriod=B.TargetPeriod
leftouterjoinChlSalesasConA.Sales=C.SalesCode
leftouterjoinChlItemCatalogasDonA.ItemCatalog=D.CatalogCode
leftouterjoinChlOrgaSEOnA.OrgID=E.OrgID
leftouterjoinChlOrgasFonC.BranchOrgID=F.OrgID',
@Condition,
N'A.TargetPerioddesc,D.CatalogName',
@PageIndex,@PageSize