[分享]扩展Row_Number分页功能,二分思路,多列混合排序。

wszhoho 2009-12-07 03:31:04
近期遇到了数据量比较大的多列排序处理,Top Max模式很难满足多列混合排序的情形,Row_number则可以,但是在末尾的分页效果已经不太如人意了,想了想二分法改造一下比较适合吧。

本存储过程适合多列排序,通用,效率不如单纯的Top Max二分法,但是要配合多列排序,还是能够接受。

可用Sql Server Profiler测试,但相关测试效果依数据量和索引合理性而定。

CREATE PROCEDURE [dbo].[DataPager]
(
@tblName nvarchar(200), ----要显示的表或多个表的连接
@fldName nvarchar(1000)='*', ----要显示的字段列表
@pageSize int = 10, ----每页显示的记录个数
@page int = 1, ----要显示那一页的记录
@pageCount int = 1 output, ----查询结果分页后的总页数
@Counts int =1 output, ----查询到的记录数
@fldSort nvarchar(100)='', ----如果多列排序,一定要带asc或者desc,则@Sort排序方法无效,反之,单列根据@Sort来处理
@Sort int = 1, ----排序方法,0为升序,1为降序
@strCondition nvarchar(1000)='', ----查询条件,不需where
@keyID nvarchar(50) = 'ID'
)
/*Create by wszhoho*/
AS
declare @sqlTmp nvarchar(2000)
declare @sqlGetCount nvarchar(2000)
declare @frontOrder nvarchar(200)
declare @behindOrder nvarchar(200)
declare @start nvarchar(20)
declare @end nvarchar(20)
begin
if @fldSort is null or @fldSort=''
set @fldSort=@keyID

if charindex(',',@fldSort,0)>0--多列排序,则@Sort排序方法无效
begin
set @frontOrder = @fldSort--获取分页前半部分数据的排序规则
set @behindOrder = replace(@frontOrder,'desc','desctmp')
set @behindOrder = replace(@behindOrder,'asc','desc')
set @behindOrder = replace(@behindOrder,'desctmp','asc')--获取分页后半部分数据的排序规则
end
else--单列
begin
set @fldSort=replace(replace(@fldSort,'desc',''),'asc','')--替换掉结尾的规则,用@Sort值来处理排序
if @Sort=1--倒序
begin
set @frontOrder = @fldSort + ' desc'
set @behindOrder = @fldSort + ' asc'
end

else
begin
set @frontOrder = @fldSort + ' asc'
set @behindOrder = @fldSort + ' desc'
end
end

--获取记录数
if @strCondition is null or @strCondition = ''--无条件
begin
set @sqlGetCount = 'select @Counts=count(*) from ' + @tblName
end
else
begin
set @sqlGetCount = 'select @Counts=count(*) from ' + @tblName + ' where ' + @strCondition
end

----取得查询结果总数量-----
exec sp_executesql @sqlGetCount,N'@Counts int out ',@Counts out
declare @tmpCounts int
if @Counts = 0
set @tmpCounts = 1
else
set @tmpCounts = @Counts

--取得分页总数
set @pageCount=(@tmpCounts+@pageSize-1)/@pageSize

/**当前页大于总页数 取最后一页**/
if @page>@pageCount
set @page=@pageCount
/*-----数据分页2分处理-------*/
declare @pageIndex int --总数/页大小
declare @lastcount int --总数%页大小 最后一页的数据量

set @pageIndex = @tmpCounts/@pageSize
set @lastcount = @tmpCounts%@pageSize
if @lastcount > 0
set @pageIndex = @pageIndex + 1
else
set @lastcount = @pagesize

--取得数据的逻辑分析
if @strCondition is null or @strCondition='' --没有设置显示条件
begin
if @pageIndex<2 or @page<=@pageIndex / 2 + @pageIndex % 2 --前半部分数据处理
begin
--计算开始结束的行号
set @start = @pageSize*(@page-1)+1
set @end = @start+@pageSize-1
set @sqlTmp='SELECT ' + @fldName + ' FROM (select '+@fldName+',ROW_NUMBER() OVER ( Order by '+@frontOrder+' ) AS RowNumber From '+@tblName+') T WHERE T.RowNumber BETWEEN '+@start+' AND '+@end+' order by '+@frontOrder
end
else
begin
set @page = @pageIndex-@page+1 --后半部分数据处理
if @lastcount=@pageSize --如果正好是整数页
begin
set @start = @pageSize*(@page-1)+1
set @end = @start+@pageSize-1
end
else
begin
set @start = @lastcount+@pageSize*(@page-2)+1
set @end = @start+@pageSize-1
end
set @sqlTmp='select top '+@end+' '+@fldName+' FROM (select '+@fldName+',ROW_NUMBER() OVER ( Order by '+@behindOrder+' ) AS RowNumber From '+@tblName+') T WHERE T.RowNumber BETWEEN '+@start+' AND '+@end+' order by '+@frontOrder
end
end
else --有查询条件
begin
if @pageIndex<2 or @page<=@pageIndex / 2 + @pageIndex % 2 --前半部分数据处理
begin
--计算开始结束的行号
set @start = @pageSize*(@page-1)+1
set @end = @start+@pageSize-1
set @sqlTmp='SELECT ' + @fldName + ' FROM (select '+@fldName+',ROW_NUMBER() OVER ( Order by '+@frontOrder+' ) AS RowNumber From '+@tblName+' where '+@strCondition+') T WHERE T.RowNumber BETWEEN '+@start+' AND '+@end+' order by '+@frontOrder
end
else
begin
set @page = @pageIndex-@page+1 --后半部分数据处理
if @lastcount=@pageSize --如果正好是整数页
begin
set @start = @pageSize*(@page-1)+1
set @end = @start+@pageSize-1
end
else
begin
set @start = @lastcount+@pageSize*(@page-2)+1
set @end = @start+@pageSize-1
end
set @sqlTmp='select top '+@end+' '+@fldName+' FROM (select '+@fldName+',ROW_NUMBER() OVER ( Order by '+@behindOrder+' ) AS RowNumber From '+@tblName+' where '+@strCondition+') T WHERE T.RowNumber BETWEEN '+@start+' AND '+@end+' order by '+@frontOrder
end
end
end
exec sp_executesql @sqlTmp
--select @sqlTmp
...全文
401 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
eamonn2008 2010-04-12
  • 打赏
  • 举报
回复
set @frontOrder = @fldSort + ' desc'
set @behindOrder = @fldSort + ' asc'
为什么倒过来啊
dc5858518 2010-02-10
  • 打赏
  • 举报
回复
测试的时候缓存去掉了吗?我认为这个执行计划应该是一样的!大家可以分析下!
wszhoho 2010-01-29
  • 打赏
  • 举报
回复
确实可以去掉,这里top加不加,对性能没有啥影响,不过我测试的时候,加了top,查询分析器里出来快点。
dc5858518 2010-01-29
  • 打赏
  • 举报
回复
select top '+@end+' '+@fldName+' FROM (select '+@fldName+',ROW_NUMBER() OVER ( Order by '+@behindOrder+' ) AS RowNumber From '+@tblName+' where '+@strCondition+') T WHERE T.RowNumber BETWEEN '+@start+' AND '+@end+' order by '+@frontOrder


个人觉得这个分页的思路并没有二分!从select '+@fldName+',ROW_NUMBER() OVER ( Order by '+@behindOrder+' ) AS RowNumber From '+@tblName+' where '+@strCondition+'这里可以看出这里依然检索了整表数据!而外层限定范围的:BETWEEN '+@start+' AND '+@end+'和top '+@end+'则显的重复!既然已经指定了范围BETWEEN '+@start+' AND '+@end+'和top '+@end+'那么又何必要:top '+@end+'?
wenyu_350 2009-12-24
  • 打赏
  • 举报
回复
需要这方面的知识哦!!呼呼~~~
messi_yang 2009-12-08
  • 打赏
  • 举报
回复
來學習了
myufo1234 2009-12-08
  • 打赏
  • 举报
回复
刚刚忘了收藏~特地回来收藏
myufo1234 2009-12-08
  • 打赏
  • 举报
回复
学习~顺便接分
nosuchtracter 2009-12-07
  • 打赏
  • 举报
回复
我在想
除了拼SQL语句还有什么高效点的吗?
很不幸,俺们的sql语句全部被过滤掉了
只能老老实实的用#table
tzs2304 2009-12-07
  • 打赏
  • 举报
回复
up
phf0313 2009-12-07
  • 打赏
  • 举报
回复
不错,不错,mark!
YnSky 2009-12-07
  • 打赏
  • 举报
回复
呵呵.不错
gongsun 2009-12-07
  • 打赏
  • 举报
回复
其实表结构中 合理化 索引 还是很重要的。
SK_Aqi 2009-12-07
  • 打赏
  • 举报
回复
jf
gongsun 2009-12-07
  • 打赏
  • 举报
回复
呵呵...
ws_hgo 2009-12-07
  • 打赏
  • 举报
回复
gz
SmallTigerWeskit 2009-12-07
  • 打赏
  • 举报
回复
up:语言被推荐
tkscascor 2009-12-07
  • 打赏
  • 举报
回复
没用sql 2005的 华丽丽的飘过!

62,046

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

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