一、分页SQL语句
方法1:适用于 SQL Server 2000/2005
SELECTTOP 页大小 *FROM table1 WHERE id NOTIN ( SELECTTOP 页大小*(页数-1) id FROM table1 ORDERBY id ) ORDERBY id
方法2:适用于 SQL Server 2000/2005
SELECTTOP 页大小 *FROM table1 WHERE id > ( SELECTISNULL(MAX(id),0) FROM ( SELECTTOP 页大小*(页数-1) id FROM table1 ORDERBY id ) A ) ORDERBY id
方法3:适用于 SQL Server 2005
SELECTTOP 页大小 *FROM ( SELECT ROW_NUMBER() OVER (ORDERBY id) AS RowNumber,*FROM table1 ) A WHERE RowNumber > 页大小*(页数-1)
说明,页大小:每页的行数;页数:第几页。使用时,请把“页大小”和“页大小*(页数-1)”替换成数字。
其它的方案:如果没有主键,可以用临时表,也可以用方案三做,但是效率会低。 建议优化的时候,加上主键和索引,查询效率会提高。
通过SQL 查询分析器,显示比较:我的结论是: 分页方案二:(利用ID大于多少和SELECT TOP分页)效率最高,需要拼接SQL语句 分页方案一:(利用Not In和SELECT TOP分页) 效率次之,需要拼接SQL语句 分页方案三:(利用SQL的游标存储过程分页) 效率最差,但是最为通用
二、分页存储过程
方法1:TOP n 实现的通用分页存储过程(转自邹建)
CREATEPROC sp_PageView @tbname sysname, --要分页显示的表名@FieldKeynvarchar(1000), --用于定位记录的主键(惟一键)字段,可以是逗号分隔的多个字段@PageCurrentint=1, --要显示的页码@PageSizeint=10, --每页的大小(记录数)@FieldShownvarchar(1000)=\'\', --以逗号分隔的要显示的字段列表,如果不指定,则显示所有字段@FieldOrdernvarchar(1000)=\'\', --以逗号分隔的排序字段列表,可以指定在字段后面指定DESC/ASC 用于指定排序顺序 @Wherenvarchar(1000)=\'\', --查询条件@PageCountint OUTPUT --总页数ASSET NOCOUNT ON--检查对象是否有效IFOBJECT_ID(@tbname) ISNULLBEGINRAISERROR(N\'对象"%s"不存在\',1,16,@tbname) RETURNENDIFOBJECTPROPERTY(OBJECT_ID(@tbname),N\'IsTable\')=0ANDOBJECTPROPERTY(OBJECT_ID(@tbname),N\'IsView\')=0ANDOBJECTPROPERTY(OBJECT_ID(@tbname),N\'IsTableFunction\')=0BEGINRAISERROR(N\'"%s"不是表、视图或者表值函数\',1,16,@tbname) RETURNEND
--分页字段检查IFISNULL(@FieldKey,N\'\')=\'\'BEGINRAISERROR(N\'分页处理需要主键(或者惟一键)\',1,16) RETURNEND
--其他参数检查及规范IFISNULL(@PageCurrent,0)<1SET@PageCurrent=1IFISNULL(@PageSize,0)<1SET@PageSize=10IFISNULL(@FieldShow,N\'\')=N\'\'SET@FieldShow=N\'*\'IFISNULL(@FieldOrder,N\'\')=N\'\'SET@FieldOrder=N\'\'ELSESET@FieldOrder=N\'ORDER BY \'+LTRIM(@FieldOrder) IFISNULL(@Where,N\'\')=N\'\'SET@Where=N\'\'ELSESET@Where=N\'WHERE (\'+@Where+N\')\'
--如果@PageCount为NULL值,则计算总页数(这样设计可以只在第一次计算总页数,以后调用时,把总页数传回给存储过程,避免再次计算总页数,对于不想计算总页数的处理而言,可以给@PageCount赋值)IF@PageCountISNULLBEGINDECLARE@sqlnvarchar(4000) SET@sql=N\'SELECT @PageCount=COUNT(*)\'+N\' FROM \'+@tbname+N\'\'+@WhereEXEC sp_executesql @sql,N\'@PageCount int OUTPUT\',@PageCount OUTPUT SET@PageCount=(@PageCount+@PageSize-1)/@PageSizeEND
--计算分页显示的TOPN值DECLARE@TopNvarchar(20),@TopN1varchar(20) SELECT@TopN=@PageSize, @TopN1=(@PageCurrent-1)*@PageSize
--第一页直接显示IF@PageCurrent=1EXEC(N\'SELECT TOP \'+@TopN+N\'\'+@FieldShow+N\' FROM \'+@tbname+N\'\'+@Where+N\'\'+@FieldOrder) ELSEBEGIN--处理别名IF@FieldShow=N\'*\'SET@FieldShow=N\'a.*\'
--生成主键(惟一键)处理条件DECLARE@Where1nvarchar(4000),@Where2nvarchar(4000), @snvarchar(1000),@Field sysname SELECT@Where1=N\'\',@Where2=N\'\',@s=@FieldKeyWHILECHARINDEX(N\',\',@s)>0SELECT@Field=LEFT(@s,CHARINDEX(N\',\',@s)-1), @s=STUFF(@s,1,CHARINDEX(N\',\',@s),N\'\'), @Where1=@Where1+N\' AND a.\'+@Field+N\'=b.\'+@Field, @Where2=@Where2+N\' AND b.\'+@Field+N\' IS NULL\', @Where=REPLACE(@Where,@Field,N\'a.\'+@Field), @FieldOrder=REPLACE(@FieldOrder,@Field,N\'a.\'+@Field), @FieldShow=REPLACE(@FieldShow,@Field,N\'a.\'+@Field) SELECT@Where=REPLACE(@Where,@s,N\'a.\'+@s), @FieldOrder=REPLACE(@FieldOrder,@s,N\'a.\'+@s), @FieldShow=REPLACE(@FieldShow,@s,N\'a.\'+@s), @Where1=STUFF(@Where1+N\' AND a.\'+@s+N\'=b.\'+@s,1,5,N\'\'), @Where2=CASEWHEN@Where=\'\'THEN N\'WHERE (\'ELSE@Where+N\' AND (\'END+N\'b.\'+@s+N\' IS NULL\'+@Where2+N\')\'--执行查询EXEC(N\'SELECT TOP \'+@TopN+N\'\'+@FieldShow+N\' FROM \'+@tbname+N\' a LEFT JOIN(SELECT TOP \'+@TopN1+N\'\'+@FieldKey+N\' FROM \'+@tbname+N\' a \'+@Where+N\'\'+@FieldOrder+N\')b ON \'+@Where1+N\'\'+@Where2+N\'\'+@FieldOrder) END
方法2:字符串缓存实现的通用分页存储过程(转自邹建)
CREATEPROC sp_PageView @tbname sysname, --要分页显示的表名@FieldKey sysname, --用于定位记录的主键(惟一键)字段,只能是单个字段@PageCurrentint=1, --要显示的页码@PageSizeint=10, --每页的大小(记录数)@FieldShownvarchar(1000)=\'\', --以逗号分隔的要显示的字段列表,如果不指定,则显示所有字段@FieldOrdernvarchar(1000)=\'\', --以逗号分隔的排序字段列表,可以指定在字段后面指定DESC/ASC 用于指定排序顺序 @Wherenvarchar(1000)=\'\', --查询条件@PageCountint OUTPUT --总页数ASDECLARE@sqlnvarchar(4000) SET NOCOUNT ON--检查对象是否有效IFOBJECT_ID(@tbname) ISNULLBEGINRAISERROR(N\'对象"%s"不存在\',1,16,@tbname) RETURNENDIFOBJECTPROPERTY(OBJECT_ID(@tbname),N\'IsTable\')=0ANDOBJECTPROPERTY(OBJECT_ID(@tbname),N\'IsView\')=0ANDOBJECTPROPERTY(OBJECT_ID(@tbname),N\'IsTableFunction\')=0BEGINRAISERROR(N\'"%s"不是表、视图或者表值函数\',1,16,@tbname) RETURNEND
--分页字段检查IFISNULL(@FieldKey,N\'\')=\'\'BEGINRAISERROR(N\'分页处理需要主键(或者惟一键)\',1,16) RETURNEND
--其他参数检查及规范IFISNULL(@PageCurrent,0)<1SET@PageCurrent=1IFISNULL(@PageSize,0)<1SET@PageSize=10IFISNULL(@FieldShow,N\'\')=N\'\'SET@FieldShow=N\'*\'IFISNULL(@FieldOrder,N\'\')=N\'\'SET@FieldOrder=N\'\'ELSESET@FieldOrder=N\'ORDER BY \'+LTRIM(@FieldOrder) IFISNULL(@Where,N\'\')=N\'\'SET@Where=N\'\'ELSESET@Where=N\'WHERE (\'+@Where+N\')\'
--如果@PageCount为NULL值,则计算总页数(这样设计可以只在第一次计算总页数,以后调用时,把总页数传回给存储过程,避免再次计算总页数,对于不想计算总页数的处理而言,可以给@PageCount赋值)IF@PageCountISNULLBEGINSET@sql=N\'SELECT @PageCount=COUNT(*)\'+N\' FROM \'+@tbname+N\'\'+@WhereEXEC sp_executesql @sql,N\'@PageCount int OUTPUT\',@PageCount OUTPUT SET@PageCount=(@PageCount+@PageSize-1)/@PageSizeEND
--计算分页显示的TOPN值DECLARE@TopNvarchar(20),@TopN1varchar(20) SELECT@TopN=@PageSize, @TopN1=@PageCurrent*@PageSize
--第一页直接显示IF@PageCurrent=1EXEC(N\'SELECT TOP \'+@TopN+N\'\'+@FieldShow+N\' FROM \'+@tbname+N\'\'+@Where+N\'\'+@FieldOrder) ELSEBEGINSELECT@PageCurrent=@TopN1, @sql=N\'SELECT @n=@n-1,@s=CASE WHEN @n<\'+@TopN+N\' THEN @s+N\'\',\'\'+QUOTENAME(RTRIM(CAST(\'+@FieldKey+N\' as varchar(8000))),N\'\'\'\'\'\'\'\') ELSE N\'\'\'\' END FROM \'+@tbname+N\'\'+@Where+N\'\'+@FieldOrderSETROWCOUNT@PageCurrentEXEC sp_executesql @sql, N\'@n int,@s nvarchar(4000) OUTPUT\', @PageCurrent,@sql OUTPUT SETROWCOUNT0IF@sql=N\'\'EXEC(N\'SELECT TOP 0\'+N\'\'+@FieldShow+N\' FROM \'+@tbname) ELSEBEGINSET@sql=STUFF(@sql,1,1,N\'\') --执行查询EXEC(N\'SELECT TOP \'+@TopN+N\'\'+@FieldShow+N\' FROM \'+@tbname+N\' WHERE \'+@FieldKey+N\' IN(\'+@sql+N\') \'+@FieldOrder) ENDEND
方法3:使用系统存储过程实现的通用分页存储过程(转自邹建)
CREATEPROC sp_PageView @sqlntext, --要执行的sql语句@PageCurrentint=1, --要显示的页码@PageSizeint=10, --每页的大小@PageCountint OUTPUT --总页数ASSET NOCOUNT ONDECLARE@p1int--初始化分页游标EXEC sp_cursoropen @cursor=@p1 OUTPUT, @stmt=@sql, @scrollopt=1, @ccopt=1, @rowcount=@PageCount OUTPUT
--计算总页数IFISNULL(@PageSize,0)<1SET@PageSize=10SET@PageCount=(@PageCount+@PageSize-1)/@PageSizeIFISNULL(@PageCurrent,0)<1ORISNULL(@PageCurrent,0)>@PageCountSET@PageCurrent=1ELSESET@PageCurrent=(@PageCurrent-1)*@PageSize+1
--显示指定页的数据EXEC sp_cursorfetch @p1,16,@PageCurrent,@PageSize
--关闭分页游标EXEC sp_cursorclose @p1
方法4:SQL 2005的ROW_NUMBER()实现分页功能
DECLARE@pagenumASINT, @pagesizeASINTSET@pagenum=2SET@pagesize=3SELECT*FROM (SELECT ROW_NUMBER() OVER(ORDERBY newsid DESC) AS rownum, newsid, topic, ntime, hits FROM news) AS D WHERE rownum BETWEEN (@pagenum-1)*@pagesize+1AND@pagenum*@pagesizeORDERBY newsid DESC
方法5:使用内存表
createproc Proc_paged ( @pagesizeint, @pagenumint, @pagecountint output ) asbegin--声明变量declare@tmptabletable(id intidentity (1,1),userid nchar(5)) declare@idBenginintdeclare@idendint--构造内存表insertinto@tmptable (userid )(select userid from users) select@pagecount=count(*) from@tmptableif(@pagecount%@pagesize>0) set@pagecount=@pagecount/@pagesize+1elseset@pagecount=@pagecount/@pagesizeset@idBengin=(@pagenum-1)*@pagesizeset@idend=@idBengin+@pagesizeselect t2.id,t1.*from users t1,@tmptable t2 where t1.userid=t2.userid and t2.id>@idBenginand t2.id<=@idendend
方法6:SQL 2005 版本 通用分页存储过程
-- ============================================= -- Author: 黄剑平 -- Create date: 2007-5-11 -- Description: SQL 2005 版本 通用分页存储过程 -- BLOG: http://www.fnsword.com -- =============================================CreatePROCEDURE[dbo].[Pagination]@Pageint=1, -- 当前页码@PageSizeint=10, -- 每页记录条数(页面大小)@Tablenvarchar(500), -- 表名或视图名,甚至可以是嵌套SQL:(Select * From Tab Where ID>1000) Tab@Fieldnvarchar(200) =\'*\', -- 返回记录集字段名,","隔开,默认是"*"@OrderBynvarchar(100) =\'ID ASC\', -- 排序规则@Filternvarchar(500), -- 过滤条件@MaxPagesmallint output, -- 执行结果 -1 error, 0 false, maxpage true@TotalRowint output, -- 记录总数 /* 2007-07-12 22:11:00 update */@Descriptvarchar(100) output -- 结果描述ASBEGINSetROWCOUNT@PageSize;
Set@Descript=\'successful\'; -------------------参数检测----------------IFLEN(RTRIM(LTRIM(@Table))) !>0BeginSet@MaxPage=0; Set@Descript=\'table name is empty\'; Return; End
IFLEN(RTRIM(LTRIM(@OrderBy))) !>0BeginSet@MaxPage=0; Set@Descript=\'order is empty\'; Return; End
IFISNULL(@PageSize,0) <=0BeginSet@MaxPage=0; Set@Descript=\'page size error\'; Return; End
IFISNULL(@Page,0) <=0BeginSet@MaxPage=0; Set@Descript=\'page error\'; Return; End-------------------检测结束----------------Begin Try -- 整合SQLDeclare@SQLnvarchar(4000), @Portionnvarchar(4000);
Set@Portion=\' ROW_NUMBER() OVER (ORDER BY \'+@OrderBy+\') AS ROWNUM FROM \'+@Table;
Set@Portion=@Portion+ (CASEWHENLEN(@Filter) >=1THEN (\' Where \'+@Filter+\') AS tab\') ELSE (\') AS tab\') END);
Set@SQL=\'Select TOP(\'+CAST(@PageSizeASnvarchar(8)) +\') \'+@Field+\' FROM (Select \'+@Field+\',\'+@Portion;
Set@SQL=@SQL+\' Where tab.ROWNUM > \'+CAST((@Page-1)*@PageSizeASnvarchar(8));
-- 执行SQL, 取当前页记录集Execute(@SQL); ---------------------------------------------------------------------- 整合SQLSet@SQL=\'Set @Rows = (Select MAX(ROWNUM) FROM (Select\'+@Portion+\')\';
-- 执行SQL, 取最大页码Execute sp_executesql @SQL, N\'@Rows int output\', @TotalRow output; Set@MaxPage= (CASEWHEN (@TotalRow%@PageSize)<>0THEN (@TotalRow/@PageSize+1) ELSE (@TotalRow/@PageSize) END); End Try Begin Catch -- 捕捉错误Set@MaxPage=-1; Set@Descript=\'error line: \'+CAST(ERROR_LINE() ASvarchar(8)) +\', error number: \'+CAST(ERROR_NUMBER() ASvarchar(8)) +\', error message: \'+ ERROR_MESSAGE(); Return; End Catch;
-- 执行成功Return; END