跪求一高效的SQL分页存储过程!

myljg 2008-07-15 02:31:53
我在网上搜索了下面这个SQL存储过程
在一百二十万条记录中测试,
以每页10为大小,查询第10000页的记录,
结果用时15秒!
求高手给个真正高效的分页存储过程!

-- 获取指定页的数据
CREATE PROCEDURE pagination
@tblName varchar(255), -- 表名
@strGetFields varchar(1000) = '*', -- 需要返回的列
@fldName varchar(255)='', -- 排序的字段名
@PageSize int = 10, -- 页尺寸
@PageIndex int = 1, -- 页码
@doCount bit = 0, -- 返回记录总数, 非 0 值则返回
@OrderType bit = 0, -- 设置排序类型, 非 0 值则降序
@strWhere varchar(1500) = '' -- 查询条件 (注意: 不要加 where)
AS
declare @strSQL varchar(5000) -- 主语句
declare @strTmp varchar(110) -- 临时变量
declare @strOrder varchar(400) -- 排序类型
if @doCount != 0
begin
if @strWhere !=''
set @strSQL = "select count(*) as Total from [" + @tblName + "] where "+@strWhere
else
set @strSQL = "select count(*) as Total from [" + @tblName + "]"
end
--以上代码的意思是如果@doCount传递过来的不是0,就执行总数统计。以下的所有代码都是@doCount为0的情况
else
begin
if @OrderType != 0
begin
set @strTmp = "<(select min"
set @strOrder = " order by [" + @fldName +"] desc"
--如果@OrderType不是0,就执行降序,这句很重要!
end
else
begin
set @strTmp = ">(select max"
set @strOrder = " order by [" + @fldName +"] asc"
end
if @PageIndex = 1
begin
if @strWhere != ''
set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from [" + @tblName + "] where " + @strWhere + " " + @strOrder
else
set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from ["+ @tblName + "] "+ @strOrder
--如果是第一页就执行以上代码,这样会加快执行速度
end
else
begin
--以下代码赋予了@strSQL以真正执行的SQL代码
set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from ["
+ @tblName + "] where [" + @fldName + "]" + @strTmp + "(["+ @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["+ @fldName + "] from [" + @tblName + "]" + @strOrder + ") as tblTmp)"+ @strOrder
if @strWhere != ''
set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from ["
+ @tblName + "] where [" + @fldName + "]" + @strTmp + "(["
+ @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["
+ @fldName + "] from [" + @tblName + "] where " + @strWhere + " "
+ @strOrder + ") as tblTmp) and " + @strWhere + " " + @strOrder
end
end
exec (@strSQL)
GO
...全文
623 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
取个昵称不难 2012-06-05
  • 打赏
  • 举报
回复
mark
ryb531 2011-03-31
  • 打赏
  • 举报
回复
mark
  • 打赏
  • 举报
回复
mark.
pzhuyy 2008-07-15
  • 打赏
  • 举报
回复
mark.
nzperfect 2008-07-15
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 hery2002 的回复:]
引用 9 楼 perfectaction 的回复:
推广机会来了:
http://www.dmblogs.com/nzBlog/article.asp?id=25
试试这个分页。

都等你好半天了~
[/Quote]

大师都了解我了,哈哈 ~
downmoon 2008-07-15
  • 打赏
  • 举报
回复
*********************************************************************************/
ALTER PROCEDURE [dbo].[ViewCPP_GetV_Product_CustomcategoryWithPage](
@pageSize int =10,@pageIndex int=0,@rowCount int =0 output,@columnClause nvarchar(500)= 'a.*',
@orderbyColumn nvarchar(500)='a.P_ID',@whereClause nvarchar(1000)='',
@orderbyClause nvarchar(200)='a.P_ID ASC',
@orderBy2Clause nvarchar(200)='a.P_ID DESC',
@ReturnRowCount bit=0
) AS

SET NOCOUNT ON
SET Transaction Isolation Level Read UNCOMMITTED
DECLARE @strSql nvarchar(4000) --定义一个存储SQL语句的变量");
DECLARE @recordBegin int
DECLARE @totalPages int
--DECLARE @strWhere2 nvarchar(100)
--DECLARE @colnmnSimple nvarchar(500)
DECLARE @currentPageSize int --当前页的记录数

DECLARE @rowCountSQL nvarchar(4000) --获得记录数的SQL
DECLARE @rowCountTable table ([rowcount] int) --临时存储记录数的表变量
DECLARE @innerJoin nvarchar(2000) --为将来关联查询做的一个内部关联
DECLARE @outputJoin nvarchar(2000) --为了关联输出结果的一个外部关联(不等于 OuterJoin)

--判断页码是否正确
IF @pageSize < 0 or @pageIndex < 0
BEGIN
RAISERROR ('传入的页码或每页记录数大小参数错误!', 16, 1)
RETURN
END

--此处可以根据需要增加关联表
SET @innerJoin = ''
--此处可以根据需要通过关联返回多表数据
SET @outputJoin = ''

--计算总记录数 开始
--只有当外部传入的总行数为零或小于零时,才去取总行数,在大于零的情况下,
--系统认为外部已经获得总行数,因此系统内部没有必要再读取一次总行数。
IF @rowCount <=0 AND @PageIndex > 0 OR @RowCount =1
BEGIN
SET @rowCountSQL = 'SELECT COUNT(*) FROM [View_ProductWithCompanyName] AS a WITH(NOLOCK) '
SET @rowCountSQL = @rowCountSQL + @innerJoin
IF NOT (@whereClause is null or RTRIM(@whereClause)='')
SET @rowCountSQL = @rowCountSQL + ' WHERE '+@whereClause

INSERT INTO @rowCountTable EXEC sp_executesql @rowCountSQL
SELECT @rowCount = [rowcount] FROM @rowCountTable
END
--计算总记录数 结束

--如果是第一页
--如果是第一页,直接处理
IF(@pageIndex=0)
BEGIN
SET @strSql = 'SELECT TOP '+CONVERT(VARCHAR(10),@pageSize)+' '+@columnClause
SET @strSql = @strSql + ' FROM [View_ProductWithCompanyName] AS a WITH(NOLOCK) '
SET @strSql = @strSql + @innerJoin
IF NOT (@whereClause is null or RTRIM(@whereClause)='')
SET @strSql = @strSql + ' WHERE '+@whereClause
SET @strSql = @strSql + @outputJoin
IF NOT (@orderbyClause is null or RTRIM(@orderbyClause)='')
SET @strSql = @strSql + ' ORDER BY '+@orderbyClause
END
ELSE
BEGIN
--计算数据的总页数
SET @totalPages = CASE WHEN @RowCount%@pageSize =0 THEN @rowCount / @pageSize ELSE @rowCount/@pageSize + 1 END

--如果是最后一页
IF(@pageIndex >= @totalPages -1)
BEGIN
--计算最后一页的行数
SET @currentPageSize = @rowCount - @pageIndex * @pageSize
WHILE(@currentPageSize < 0)
BEGIN
SET @currentPageSize = @pageSize + @currentPageSize
END

SET @strSql = 'SELECT TOP '+CONVERT(VARCHAR(10),@currentPageSize)+' '+ @columnClause
SET @strSql = @strSql +char(10)+char(13)+ ' FROM [View_ProductWithCompanyName] AS a WITH(NOLOCK) '
SET @strSql = @strSql +char(10)+char(13)+ ' INNER JOIN ( '
SET @strSql = @strSql +char(10)+char(13)+ ' SELECT TOP '+CONVERT(VARCHAR(10),@currentPageSize)+' P_ID '
SET @strSql = @strSql +char(10)+char(13)+ ' FROM [View_ProductWithCompanyName] AS a WITH(NOLOCK) '
SET @strSql = @strSql + @innerJoin
IF NOT (@whereClause is null or RTRIM(@whereClause)='')
SET @strSql = @strSql +char(10)+char(13)+ ' WHERE '+@whereClause

IF NOT (@orderby2Clause is null or RTRIM(@orderby2Clause)='')
SET @strSql = @strSql +char(10)+char(13)+ ' ORDER BY '+@orderby2Clause

SET @strSql = @strSql + ' ) AS c '
SET @strSql = @strSql + ' ON a.P_ID = c.p_ID '
SET @strSql = @strSql + @outputJoin
IF NOT (@orderbyClause is null or RTRIM(@orderbyClause)='')
SET @strSql = @strSql +char(10)+char(13)+ ' ORDER BY '+@orderbyClause
END

ELSE
BEGIN
--如果在前半数的记录页
IF(@pageIndex <= @totalPages/2)
BEGIN
SET @strSql = 'SELECT TOP '+CONVERT(VARCHAR(10),@pageSize)+' '+@columnClause
SET @strSql = @strSql +char(10)+char(13)+ ' FROM [View_ProductWithCompanyName] AS a WITH(NOLOCK) '
SET @strSql = @strSql +char(10)+char(13)+ ' INNER JOIN ( '
SET @strSql = @strSql +char(10)+char(13)+ ' SELECT TOP '+CONVERT(VARCHAR(10),@pageSize)+' * FROM ('
SET @strSql = @strSql +char(10)+char(13)+ ' SELECT TOP '+CONVERT(VARCHAR(10),@pageSize * (@pageIndex+1))+' '+@orderbyColumn
SET @strSql = @strSql +char(10)+char(13)+ ' FROM [View_ProductWithCompanyName] AS a '
SET @strSql = @strSql +char(10)+char(13)+ @innerJoin
IF NOT (@whereClause is null or RTRIM(@whereClause)='')
SET @strSql = @strSql + ' WHERE '+@whereClause
IF NOT (@orderbyClause is null or RTRIM(@orderbyClause)='')
SET @strSql = @strSql + ' ORDER BY '+@orderbyClause

SET @strSql = @strSql + ' ) AS a '
SET @strSql = @strSql +char(10)+char(13)+ ' ORDER BY '+@orderby2Clause
SET @strSql = @strSql +char(10)+char(13)+ ' ) AS C '
SET @strSql = @strSql + ' ON a.P_ID = c.p_ID '
SET @strSql = @strSql + @outputJoin
IF NOT (@orderbyClause is null or RTRIM(@orderbyClause)='')
SET @strSql = @strSql + ' ORDER BY '+@orderbyClause

END
ELSE
BEGIN
--如果是后半数页
SET @strSql = ' SELECT TOP '+CONVERT(VARCHAR(10),@pageSize)+ ' '+@columnClause
SET @strSql = @strSql + ' FROM [View_ProductWithCompanyName] AS a WITH(NOLOCK) '
SET @strSql = @strSql +char(10)+char(13)+ ' INNER JOIN ( '
SET @strSql = @strSql +char(10)+char(13)+ 'SELECT TOP '+CONVERT(VARCHAR(10),@rowCount - @pageSize * @pageIndex)+' '+@orderbyColumn
SET @strSql = @strSql + ' FROM [View_ProductWithCompanyName] AS a '
SET @strSql = @strSql + @innerJoin
IF NOT (@whereClause is null or RTRIM(@whereClause)='')
SET @strSql = @strSql + ' WHERE '+@whereClause

IF NOT (@orderbyClause is null or RTRIM(@orderbyClause)='')
SET @strSql = @strSql + ' ORDER BY '+@orderby2Clause

SET @strSql = @strSql +char(10)+char(13)+ ' ) AS C '
SET @strSql = @strSql + ' ON a.P_ID = c.p_ID '
SET @strSql = @strSql + @outputJoin
IF NOT (@orderbyClause is null or RTRIM(@orderbyClause)='')
SET @strSql = @strSql +char(10)+char(13)+ ' ORDER BY '+@orderbyClause

END
END
END
EXEC(@strSql)

RETURN @rowcount
downmoon 2008-07-15
  • 打赏
  • 举报
回复
----select * from View_ProductWithCompanyName
--ViewCPP_GetV_Product_CustomcategoryWithPage 10,7,0,'a.*','a.P_ID','1=1','a.P_ID ASC','a.P_ID DESC',0

/*********************************************************************************
-- 功能:从表V_Product_Customcategory中分页提取数据调用方式
-- 具体描述:分页读取表中的数据,可以通过修改达到多表关联取出分页数据的目的。
-- 调用示例:EXEC upc_GetV_Product_CustomcategoryWithPage
-- 参数: @pageSize int 每页数据大小 //用于识别正确值及需要修改的值
-- 参数: @pageIndex int 当前是第几页,第一页为0,第二页为1,类推。如果页号大于数据最大页数,将自动调整为最后一页 //用于识别正确值及需要修改的值
-- 参数: @rowCount int 符合where条件的所有记录个数 //用于识别正确值及需要修改的值
-- 参数: @columnClause nvarchar(500) 输出的字段条件,如a.columnA,a.columnB,用逗号分开,必需包含唯一关键字及需要排序的字段(即在orderbyclause中的字段) //用于识别正确值及需要修改的值
-- 参数: @orderbyColumn nvarchar(500) 排序的条件涉及的字段,如columnA ,ColumnB 等格式,这里的列名应该包今一个关键字和需要排序的字段 //用于识别正确值及需要修改的值
-- 参数: @whereClause nvarchar(1000) 提取数据的条件 //用于识别正确值及需要修改的值
-- 参数: @orderbyClause nvarchar(200) 排序的条件,如columnA ASC,ColumnB desc等格式 //用于识别正确值及需要修改的值
-- 参数: @orderby2Clause nvarchar(200) 排序的条件的反向条件,如columnA ASC,ColumnB desc等格式 //用于识别正确值及需要修改的值
-- 参数: @returnRowCount bit 是否需要返回RowCount,因为如果取第一页数据,可以不用去查询总行数,默认值为0,即不强制返回。当然,如果不是第一页,则一定会返回RowCount。
-- 返回值说明:返回符合条件的记录集合
-- 涉及库/表:V_Product_Customcategory
-- 在何处使用(具体到页面):
-- 创建者/创建日期: / 2008-06-27 08:51:38
-- 修改内容:
hery2002 2008-07-15
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 perfectaction 的回复:]
推广机会来了:
http://www.dmblogs.com/nzBlog/article.asp?id=25
试试这个分页。
[/Quote]
都等你好半天了~
nzperfect 2008-07-15
  • 打赏
  • 举报
回复
推广机会来了:
http://www.dmblogs.com/nzBlog/article.asp?id=25

试试这个分页。
正宗老冉 2008-07-15
  • 打赏
  • 举报
回复
去看精华帖.
  • 打赏
  • 举报
回复
CREATE proc Pagination
@a_TableList Varchar(200), --要查询的字段
@a_TableName Varchar(30), --要查询的表名
@a_SelectWhere Varchar(500), --查询限制条件
@a_SelectOrderId Varchar(20), --查询主键
@a_SelectOrder Varchar(50), --排序字段
@a_intPageNo int,
@a_intPageSize int,
@RecordCount int OUTPUT
as
/**//*定义局部变量*/
declare @intBeginID int
declare @intEndID int
declare @intRootRecordCount int
declare @intRowCount int
declare @TmpSelect NVarchar(600)
/**//*关闭计数*/
set nocount on

/**//*求总共根贴数*/

select @TmpSelect = 'set nocount on;select @SPintRootRecordCount = count(*) from '+@a_TableName+' '+@a_SelectWhere
execute sp_executesql
@TmpSelect,
N'@SPintRootRecordCount int OUTPUT',
@SPintRootRecordCount=@intRootRecordCount OUTPUT

select @RecordCount = @intRootRecordCount

if (@intRootRecordCount = 0) --如果没有贴子,则返回零
return 0

/**//*判断页数是否正确*/
if (@a_intPageNo - 1) * @a_intPageSize > @intRootRecordCount
return (-1)

/**//*求开始rootID*/
set @intRowCount = (@a_intPageNo - 1) * @a_intPageSize + 1
/**//*限制条数*/

select @TmpSelect = 'set nocount on;set rowcount @SPintRowCount;select @SPintBeginID = '+@a_SelectOrderId+' from '+@a_TableName+' '+@a_SelectWhere+' '+@a_SelectOrder
execute sp_executesql
@TmpSelect,
N'@SPintRowCount int,@SPintBeginID int OUTPUT',
@SPintRowCount=@intRowCount,@SPintBeginID=@intBeginID OUTPUT


/**//*结束rootID*/
set @intRowCount = @a_intPageNo * @a_intPageSize
/**//*限制条数*/

select @TmpSelect = 'set nocount on;set rowcount @SPintRowCount;select @SPintEndID = '+@a_SelectOrderId+' from '+@a_TableName+' '+@a_SelectWhere+' '+@a_SelectOrder
execute sp_executesql
@TmpSelect,
N'@SPintRowCount int,@SPintEndID int OUTPUT',
@SPintRowCount=@intRowCount,@SPintEndID=@intEndID OUTPUT


if @a_SelectWhere='' or @a_SelectWhere IS NULL
select @TmpSelect = 'set nocount off;set rowcount 0;select '+@a_TableList+' from '+@a_TableName+' where '+@a_SelectOrderId+' between '
else
select @TmpSelect = 'set nocount off;set rowcount 0;select '+@a_TableList+' from '+@a_TableName+' '+@a_SelectWhere+' and '+@a_SelectOrderId+' between '

if @intEndID > @intBeginID
select @TmpSelect = @TmpSelect+'@SPintBeginID and @SPintEndID'+' '+@a_SelectOrder
else
select @TmpSelect = @TmpSelect+'@SPintEndID and @SPintBeginID'+' '+@a_SelectOrder

execute sp_executesql
@TmpSelect,
N'@SPintEndID int,@SPintBeginID int',
@SPintEndID=@intEndID,@SPintBeginID=@intBeginID

return(@@rowcount)
--select @@rowcount

GO
utpcb 2008-07-15
  • 打赏
  • 举报
回复
最好不要用游标!网上有很多你去 baidu 一下呵呵
中国风 2008-07-15
  • 打赏
  • 举报
回复
/*--用存储过程实现的分页程序

显示指定表、视图、查询结果的第X页
对于表中主键或标识列的情况,直接从原表取数查询,其它情况使用临时表的方法
如果视图或查询结果中有主键,不推荐此方法

--邹建 2003.09(引用请保留此信息)--*/

/*--调用示例
exec p_show '地区资料'

exec p_show '地区资料',5,3,'地区编号,地区名称,助记码','地区编号'
--*/

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[p_show]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[p_show]
GO

CREATE Proc p_show
@QueryStr nvarchar(4000), --表名、视图名、查询语句
@PageSize int=10, --每页的大小(行数)
@PageCurrent int=1, --要显示的页
@FdShow nvarchar (4000)='', --要显示的字段列表,如果查询结果有标识字段,需要指定此值,且不包含标识字段
@FdOrder nvarchar (1000)='' --排序字段列表
as
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(@QueryStr)
,@FdShow=case isnull(@FdShow,'') when '' then ' *' else ' '+@FdShow end
,@FdOrder=case isnull(@FdOrder,'') when '' then '' else ' order by '+@FdOrder end
,@QueryStr=case when @Obj_ID is not null then ' '+@QueryStr else ' ('+@QueryStr+') a' end

--如果显示第一页,可以直接用top来完成
if @PageCurrent=1
begin
select @Id1=cast(@PageSize as varchar(20))
exec('select top '+@Id1+@FdShow+' from '+@QueryStr+@FdOrder)
return
end

--如果是表,则检查表中是否有标识更或主键
if @Obj_ID is not null and objectproperty(@Obj_ID,'IsTable')=1
begin
select @Id1=cast(@PageSize as varchar(20))
,@Id2=cast((@PageCurrent-1)*@PageSize 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:
exec('select top '+@Id1+@FdShow+' from '+@QueryStr
+' where '+@FdName+' not in(select top '
+@Id2+' '+@FdName+' from '+@QueryStr+@FdOrder
+')'+@FdOrder
)
return

/*--表中有复合主键的处理方法--*/
lbusepk:
exec('select '+@FdShow+' from(select top '+@Id1+' a.* from
(select top 100 percent * from '+@QueryStr+@FdOrder+') a
left join (select top '+@Id2+' '+@strfd+'
from '+@QueryStr+@FdOrder+') b on '+@strjoin+'
where '+@strwhere+') a'
)
return

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

exec('select '+@FdName+'=identity(int,0,1),'+@FdShow+'
into #tb from'+@QueryStr+@FdOrder+'
select '+@FdShow+' from #tb where '+@FdName+' between '
+@Id1+' and '+@Id2
)

GO

-狙击手- 2008-07-15
  • 打赏
  • 举报
回复
 --TOP n 实现的通用分页排序存储过程
--exec sp_PageView t,'ID',1,5,'ID,sex,Name','ID asc','ID=1',1
CREATE PROC sp_PageView
@tbname sysname, --要分页显示的表名
@FieldKey nvarchar(1000), --用于定位记录的主键(惟一键)字段,可以是逗号分隔的多个字段
@PageCurrent int=1, --要显示的页码
@PageSize int=10, --每页的大小(记录数)
@FieldShow nvarchar(1000)='', --以逗号分隔的要显示的字段列表,如果不指定,则显示所有字段
@FieldOrder nvarchar(1000)='', --以逗号分隔的排序字段列表,可以指定在字段后面指定DESC/ASC
--用于指定排序顺序
@Where nvarchar(1000)='', --查询条件
@PageCount int OUTPUT --总页数
AS
SET NOCOUNT ON
--检查对象是否有效
IF OBJECT_ID(@tbname) IS NULL
BEGIN
RAISERROR(N'对象"%s"不存在',1,16,@tbname)
RETURN
END
IF OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsTable')=0
AND OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsView')=0
AND OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsTableFunction')=0
BEGIN
RAISERROR(N'"%s"不是表、视图或者表值函数',1,16,@tbname)
RETURN
END

--分页字段检查
IF ISNULL(@FieldKey,N'')=''
BEGIN
RAISERROR(N'分页处理需要主键(或者惟一键)',1,16)
RETURN
END

--其他参数检查及规范
IF ISNULL(@PageCurrent,0)<1 SET @PageCurrent=1
IF ISNULL(@PageSize,0)<1 SET @PageSize=10
IF ISNULL(@FieldShow,N'')=N'' SET @FieldShow=N'*'
IF ISNULL(@FieldOrder,N'')=N''
SET @FieldOrder=N''
ELSE
SET @FieldOrder=N'ORDER BY '+LTRIM(@FieldOrder)
IF ISNULL(@Where,N'')=N''
SET @Where=N''
ELSE
SET @Where=N'WHERE ('+@Where+N')'

--如果@PageCount为NULL值,则计算总页数(这样设计可以只在第一次计算总页数,以后调用时,把总页数传回给存储过程,避免再次计算总页数,对于不想计算总页数的处理而言,可以给@PageCount赋值)
IF @PageCount IS NULL
BEGIN
DECLARE @sql nvarchar(4000)
SET @sql=N'SELECT @PageCount=COUNT(*)'
+N' FROM '+@tbname
+N' '+@Where
EXEC sp_executesql @sql,N'@PageCount int OUTPUT',@PageCount OUTPUT
SET @PageCount=(@PageCount+@PageSize-1)/@PageSize
END

--计算分页显示的TOPN值
DECLARE @TopN varchar(20),@TopN1 varchar(20)
SELECT @TopN=@PageSize,
@TopN1=(@PageCurrent-1)*@PageSize

--第一页直接显示
IF @PageCurrent=1
EXEC(N'SELECT TOP '+@TopN
+N' '+@FieldShow
+N' FROM '+@tbname
+N' '+@Where
+N' '+@FieldOrder)
ELSE
BEGIN
--处理别名
IF @FieldShow=N'*'
SET @FieldShow=N'a.*'

--生成主键(惟一键)处理条件
DECLARE @Where1 nvarchar(4000),@Where2 nvarchar(4000),
@s nvarchar(1000),@Field sysname
SELECT @Where1=N'',@Where2=N'',@s=@FieldKey
WHILE CHARINDEX(N',',@s)>0
SELECT @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=CASE
WHEN @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
GO
-狙击手- 2008-07-15
  • 打赏
  • 举报
回复
CREATE Proc p_show 
@QueryStr nvarchar(4000), --表名、视图名、查询语句
@PageSize int=10, --每页的大小(行数)
@PageCurrent int=1, --要显示的页
@FdShow nvarchar (4000)= ' ', --要显示的字段列表,如果查询结果有标识字段,需要指定此值,且不包含标识字段
@FdOrder nvarchar (1000)= ' ' --排序字段列表
as
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(@QueryStr)
,@FdShow=case isnull(@FdShow, ' ') when ' ' then ' * ' else ' '+@FdShow end
,@FdOrder=case isnull(@FdOrder, ' ') when ' ' then ' ' else ' order by '+@FdOrder end
,@QueryStr=case when @Obj_ID is not null then ' '+@QueryStr else ' ( '+@QueryStr+ ') a ' end

--如果显示第一页,可以直接用top来完成
if @PageCurrent=1
begin
select @Id1=cast(@PageSize as varchar(20))
exec( 'select top '+@Id1+@FdShow+ ' from '+@QueryStr+@FdOrder)
return
end

--如果是表,则检查表中是否有标识更或主键
if @Obj_ID is not null and objectproperty(@Obj_ID, 'IsTable ')=1
begin
select @Id1=cast(@PageSize as varchar(20))
,@Id2=cast((@PageCurrent-1)*@PageSize 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:
exec( 'select top '+@Id1+@FdShow+ ' from '+@QueryStr
+ ' where '+@FdName+ ' not in(select top '
+@Id2+ ' '+@FdName+ ' from '+@QueryStr+@FdOrder
+ ') '+@FdOrder
)
return

/*--表中有复合主键的处理方法--*/
lbusepk:
exec( 'select '+@FdShow+ ' from(select top '+@Id1+ ' a.* from
(select top 100 percent * from '+@QueryStr+@FdOrder+ ') a
left join (select top '+@Id2+ ' '+@strfd+ '
from '+@QueryStr+@FdOrder+ ') b on '+@strjoin+ '
where '+@strwhere+ ') a '
)
return

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

exec( 'select '+@FdName+ '=identity(int,0,1), '+@FdShow+ '
into #tb from '+@QueryStr+@FdOrder+ '
select '+@FdShow+ ' from #tb where '+@FdName+ ' between '
+@Id1+ ' and '+@Id2
)

GO


create table ta(col1 int,col2 char(2))
go
insert ta select 1,'2'

exec p_show '(select * from ta)',10,1,'col1,col2','col2'


drop table ta
drop proc p_show

/*

col1 col2
----------- ----
1 2

(所影响的行数为 1 行)
*/



-狙击手- 2008-07-15
  • 打赏
  • 举报
回复
 
2----------------


CREATE PROCEDURE GetRecordFromPage
@tblName varchar(255), -- 表名
@fldName varchar(255), -- 字段名
@PageSize int = 10, -- 页尺寸
@PageIndex int = 1, -- 页码
@IsCount bit = 0, -- 返回记录总数, 非 0 值则返回
@OrderType bit = 0, -- 设置排序类型, 非 0 值则降序
@strWhere varchar(1000) = '' -- 查询条件 (注意: 不要加 where)
AS

declare @strSQL varchar(1000) -- 主语句
declare @strTmp varchar(300) -- 临时变量
declare @strOrder varchar(400) -- 排序类型

if @OrderType != 0
begin
set @strTmp = "<(select min"
set @strOrder = " order by [" + @fldName +"] desc"
end
else
begin
set @strTmp = ">(select max"
set @strOrder = " order by [" + @fldName +"] asc"
end

set @strSQL = "select top " + str(@PageSize) + " * from ["
+ @tblName + "] where [" + @fldName + "]" + @strTmp + "(["
+ @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["
+ @fldName + "] from [" + @tblName + "]" + @strOrder + ") as tblTmp)"
+ @strOrder

if @strWhere != ''
set @strSQL = "select top " + str(@PageSize) + " * from ["
+ @tblName + "] where [" + @fldName + "]" + @strTmp + "(["
+ @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["
+ @fldName + "] from [" + @tblName + "] where (" + @strWhere + ") "
+ @strOrder + ") as tblTmp) and (" + @strWhere + ") " + @strOrder

if @PageIndex = 1
begin
set @strTmp = ""
if @strWhere != ''
set @strTmp = " where (" + @strWhere + ")"

set @strSQL = "select top " + str(@PageSize) + " * from ["
+ @tblName + "]" + @strTmp + " " + @strOrder
end

if @IsCount != 0
set @strSQL = "select count(*) as Total from [" + @tblName + "]"

exec (@strSQL)
GO
-狙击手- 2008-07-15
  • 打赏
  • 举报
回复
1------------------------------------------------
--游标不是明智的选择,在小数据量时可以使用
create procedure hahaha
@sqlstr nvarchar(4000), --查询字符串
@currentpage int, --第N页
@pagesize int --每页行数
as
set nocount on
declare @P1 int, --P1是游标的id
@rowcount int
exec sp_cursoropen @P1 output,@sqlstr,@scrollopt=1,@ccopt=1,@rowcount=@rowcount output
select ceiling(1.0*@rowcount/@pagesize) as 总页数--,@rowcount as 总行数,@currentpage as 当前页
set @currentpage=(@currentpage-1)*@pagesize+1
exec sp_cursorfetch @P1,16,@currentpage,@pagesize
exec sp_cursorclose @P1
set nocount off

测试: hahaha '任何条件的SQL语句',2,10

22,301

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧