按任意字段排序的分页存储过程
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(4000) = '' -- 查询条件 (注意: 不要加 where)
AS
declare @strSQL varchar(6000) -- 主语句
declare @strTmp varchar(6000) -- 临时变量
declare @strOrder varchar(6000) -- 排序类型
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 这个分页存储过程我一直用于某些场所,如果大家用过,相信应该比较认可它的性能,可是,从代码中,我们看到,它有一个基本的要求,即是表或视图必定有一个主键,隐含的要求是排序字段必须是一个具备唯一值的字段,这在我上面提到的应用是不可能满足的,所以,这个存储过程虽然有用,可是,在这个场合,却用不上
后来看到CNBLOGS上另一位仁兄谈到的关于ASP.NET FORUM使用的临时表分页法,就写了一个临时表的分页存储过程,也是通用的,实现起来比较上的方法还要容易,如下
CREATE PROCEDURE dbo.GetPageRecord
(
@tblName varchar(255), -- 表名
@fldlist varchar(1000)='*',
@fldName varchar(255), --排序字段
@KeyField varchar(255), --主键
@PageSize int = 10, -- 页尺寸
@PageIndex int = 1, -- 页码
@IsCount bit = 0, -- 返回记录总数, 非 0 值则返回
@OrderType bit = 1, -- 设置排序类型, 非 0 值则降序
@strWhere varchar(4000) = '' -- 查询条件 (注意: 不要加 where)
)
AS
SET NOCOUNT ON
DECLARE @PageLowerBound int
DECLARE @PageUpperBound int
-- Set the page bounds
SET @PageLowerBound = @PageSize * @PageIndex
SET @PageUpperBound = @PageLowerBound + @PageSize + 1
-- Create a temp table to store the select results
create table #temp
(
RecNo int IDENTITY (1, 1) NOT NULL,
oldid int
)
--generate record
Declare @Sqlstr varchar(6000)
set @sqlstr='select '+@Keyfield+' from '+@tblname
if(@strWhere<>'')
begin
set @Sqlstr=@sqlstr+' where ('+@strWhere+')'
end
set @sqlstr=@sqlstr+' order by '+@fldName
if(@ordertype=0)
begin
set @sqlstr=@sqlstr+' asc'
end
else
begin
set @sqlstr=@sqlstr+' desc'
end
set @sqlstr='insert into #temp (oldid) '+@sqlstr
execute(@sqlstr)
set @sqlstr='SELECT '+@fldList+' FROM '+@tblname+' TableA (nolock), #temp T WHERE T.oldid = TableA.'+@keyfield+' AND T.RecNo > '+ cast(@PageLowerBound as varchar)+' AND T.RecNo < '+cast(@PageUpperBound as varchar)+' ORDER BY T.RecNo'
execute(@sqlstr)
GO
第一个秘密是关于SELECT语句的:
SQL中的SELECT语句可以将另外一个SELECT语句作为内容来源,并且按此规律进行嵌套处理,但是,有一个前提,必须对作为来源的SELEC结果集指定别名,下面是一个示例性SQL语句,你可以在查询分析器里证实它:
select top 10 * from (select top 100 * from tblproducts where name like '%mp3%' order by id desc) as a order by id desc 请相信你的眼睛,上面的语句确实能执行,可能你曾经试过执行类似的语句但并未成功,那是因为你没有将来源结果集指定别名
第二个秘密是一个规则:
如果你想用select top 20*4的方式在SQL中取前80条记录,你会失败,因为TOP子句有一个限制,就是TOP num中的num不能是一个计算值或表达式而必须是一个既定的常量
第三个秘密足够重大,我想,应该很少有人发现它,否则的话,很多问题便会变得简单起来,简要的说,它就是:SQL允许你用EXECUTE执行一个变量中定义的SQL语句,并且允许你在被执行的SQL语句中,再次嵌套入一个变量定义的语句,并且再次在其中用EXECUTE执行它,如果语言不足以证明,那么下面的代码将证明这是行得通并且是很好的
declare @sqlstr varchar(3000)
set @sqlstr='declare @subsqlstr varchar(1000);'
set @sqlstr=@sqlstr+'set @subsqlstr=''select * from tblproducts'';'
set @sqlstr=@sqlstr+'execute (@subsqlstr)'
execute(@sqlstr)
在上面的代码中,@SQL变量中定义的是一组SQL语句,在这组SQL语句中,又定义了一个@SUBSQL变量,在其中存放了SELECT语句,
所以,当系统执行@SQLSTR时,其中定义的变量会被执行,执行的结果是,构造了一组动态执行的SQL语句,将其存入了变量,最后,在EXECUTE中又被执行,这种嵌套的执行,我们就姑且称其为动态执行能力吧
不过,需要相当注意的是:
1,由于在变量中存放语句组,因此,且莫忘记在每一个语句末尾加上分号(分号是SQL一句语句的结束标志)
2,如果在语句中包含变量的赋值,请记住你是在写一个变量赋值语句,因此记住加上单引号将值括起
3,如果你在变量中定义的语句组中要引用字符串常量,请先将单引号替换成两个单引号
最后,我用上面的方法写了两种SQL通用分页存储过程:
它们具有以下特点1,支持字段集合选择,2支持任意字段排序,
上面的图,我们以最终结果集倒序为例,第一种方案,我们先取集集合OB,这可以用一个使用SELECT TOP 并使用升级排列的语句完成
然后对OB结果集进行倒序排序,再用"SELECT TOP 每页记录数"倒序 的方式取得目标集合AB,下面是存储过程
create PROCEDURE dbo.GetPagingData
(
@tablename varchar(100),--表名或视图表
@fieldlist varchar(4000)='*',--欲选择字段列表
@orderfield varchar(100),--排序字段
@keyfield varchar(100),--主键
@pageindex int,--页号,从0开始
@pagesize int=20,--页尺寸
@strwhere varchar(4000),--条件
@ordertype bit=1--排序,1,降序,0,升序
)
AS
/**//*
名称:GetPagingRecord
作用:按任意字段进行排序分页
*/
SET NOCOUNT ON
declare @sqlstr varchar(6000)
--处理SQL中危险字符,并且将条件处理成易嵌入的形式
set @sqlstr='declare @Rcount int;'
set @sqlstr=@sqlstr+'set @rcount=(select count('+@keyfield+') from '+@tablename+' where '+@strWhere+');'
set @strwhere=replace(@strwhere,'''','''''')
set @strwhere=replace(@strwhere,'--','')
set @strwhere=replace(@strwhere,';','')
set @sqlstr=@sqlstr+'declare @Rnum int;'
set @sqlstr=@sqlstr+'set @rnum=@rcount-'+cast(@pagesize as varchar)+'*'+cast(@pageindex as varchar)+';'
set @sqlstr=@sqlstr+'declare @sqlstr varchar(6000);'
if @ordertype=1
begin
set @sqlstr=@sqlstr+'set @sqlstr=''select top '+cast(@Pagesize as varchar)+' '+@fieldlist+' from (select top 100
percent * from (select top ''+cast(@rnum as varchar)+'' * from '+@tablename+' where '+@strwhere+'
order by '+@orderfield+' asc) as b order by paymoney desc) as a order by '+@orderfield+' desc '';'
end
else
begin
set @sqlstr=@sqlstr+'set @sqlstr=''select top '+cast(@Pagesize as varchar)+' '+@fieldlist+' from (select top 100
percent * from (select top ''+cast(@rnum as varchar)+'' * from '+@tablename+' where '+@strwhere+'
order by '+@orderfield+' desc) as b order by paymoney asc) as a order by '+@orderfield+' asc '';'
end
set @sqlstr=@sqlstr+'if @Rcount>0 begin execute(@sqlstr) end'
--print @sqlstr
execute(@sqlstr)
在上面的代码中,还处理了没有符合条件结果的情况
第二种方案的思想是这样的,先用倒序的SELECT TOP (页序号+1)*页尺寸的方法取得AE结果集,再从AE结果集中用NOT IN 的方法排除掉用SELECT TOP 页序号*页尺寸的方法取得的结果集,最后,对目标结果集执行倒序,下面是实现的代码
create PROCEDURE dbo.GetPagingRecord
(
@tablename varchar(100),--表名或视图表
@fieldlist varchar(4000)='*',--欲选择字段列表
@orderfield varchar(100),--排序字段
@keyfield varchar(100),--主键
@pageindex int,--页号,从0开始
@pagesize int=20,--页尺寸
@strwhere varchar(4000),--条件
@ordertype bit=1--排序,1,降序,0,升序
)
AS
/**//*
名称:GetPagingRecord
作用:按任意字段进行排序分页
作者:菩提树(MARK MA)
时间:2004-12-14
声明:此代码你可以无偿使用及转载,但在转载时,请勿移称本文字声明
*/
SET NOCOUNT ON
declare @sqlstr varchar(6000)
--处理SQL中危险字符,并且将条件处理成易嵌入的形式
set @strwhere=replace(@strwhere,'''','''''')
set @strwhere=replace(@strwhere,'--','')
set @strwhere=replace(@strwhere,';','')
set @sqlstr='declare @CurPageNum int;'
set @sqlstr=@sqlstr+'declare @nextpagenum int;'
set @sqlstr=@sqlstr+'set @curpagenum='+cast(@PageIndex as varchar)+'*'+cast(@Pagesize as varchar)+';'
set @sqlstr=@sqlstr+'set @nextpagenum='+cast(@PageIndex+1 as varchar)+'*'+cast(@Pagesize as varchar)+';'
set @sqlstr=@sqlstr+'declare @sqlstr varchar(6000);'
if @ordertype=1
begin
set @sqlstr=@sqlstr+'set @sqlstr=''select '+@fieldlist+' from ( select top ''+cast(@nextpagenum as varchar)+'' * from
'+@tablename+' where '+@strwhere+' order by '+@orderfield+' desc ) as a where '+@keyfield+' not in (
select top ''+cast(@curpagenum as varchar)+'' '+@keyfield+' from '+@tablename+' where '+@strwhere+'
order by '+@orderfield+' desc) order by '+@orderfield+' desc'';'
end
else
begin
set @sqlstr=@sqlstr+'set @sqlstr=''select '+@fieldlist+' from ( select top ''+cast(@nextpagenum as varchar)+'' * from
'+@tablename+' where '+@strwhere+' order by '+@orderfield+' asc ) as a where '+@keyfield+' not in (
select top ''+cast(@curpagenum as varchar)+'' '+@keyfield+' from '+@tablename+' where '+@strwhere+'
order by '+@orderfield+' asc) order by '+@orderfield+' asc'';'
end
set @sqlstr=@sqlstr+'execute( @sqlstr)'
--print @sqlstr
execute(@sqlstr)
需要注意的是,如果要避免SQL注入式***,请注意处理像分号,双减号,单引号这些在SQL中有特殊含义的字符
至于上面两个存储过程哪个性能更好,那就取决于是对一个倒序的结果集再进入一次反序排列好呢,还是用NOT IN从一个大的结果集移除一个小的结果集好
学术名叫 derived table
上面这个实现的方法应该知道的人不少吧?
需要唯一主键的原因是可以用in
使用From子句”这个主题也提到关于在From子句中把另一个Select子句作为参数的使用方法。
子查询的的勘套.以及连接查询 子查询里面的连接查询不要使用同样的字段名,不然外面勘套的 select * 要报错。考虑性能最好不要用in 和 not in.
用以上代码修改的兼容网上流行的"通用分页存储过程"
CREATE PROCEDURE pagination
(
@tablename varchar(255), --表名或视图表
@fieldlist varchar(1000)='*', --欲选择字段列表
@orderfield varchar(255)='', --排序字段
@pagesize int=10, --页尺寸
@pageindex int=1, --页号
@docount bit=0, --返回记录总数, 非 0 值则返回
@ordertype bit=0, --排序,1,降序,0,升序
@strwhere varchar(1500)='' -- 查询条件 (注意: 不要加 where)
)
AS
/*
名称:GetPagingRecord
作用:按任意字段进行排序分页
作者:菩提树(MARK MA)
时间:2004-12-14
声明:此代码你可以无偿使用及转载,但在转载时,请勿移称本文字声明
修改:木木(mumuqz) 2005-09-14
*/
SET NOCOUNT ON
declare @sqlstr varchar(6000)
set @sqlstr='declare @rcount int;'
if @doCount != 0 -----------------------------------------------统计总记录数
begin
if @strwhere !=''
begin
set @sqlstr = 'select count(*) as Total from ' + @tablename + ' where '+@strwhere
set @strwhere=replace(@strwhere,'''','''''') ------处理SQL中危险字符,并且将条件处理成易嵌入的形式
set @strwhere=replace(@strwhere,'--','')
set @strwhere=replace(@strwhere,';','')
end
else
begin
set @sqlstr = 'select count(*) as Total from ' + @tablename
end
end
else -----------------------------------------------------------分页显示记录
begin
if @strwhere !='' ----------------------------------------当查询条件不为空
begin
set @sqlstr=@sqlstr+'set @rcount=(select count(*) from '+@tablename+' where '+@strwhere+');'
set @strwhere=replace(@strwhere,'''','''''')
set @strwhere=replace(@strwhere,'--','')
set @strwhere=replace(@strwhere,';','')
set @sqlstr=@sqlstr+'declare @rnum int;'
set @sqlstr=@sqlstr+'set @rnum=@rcount-'+cast(@pagesize as varchar)+'*('+cast(@pageindex as varchar)+'-1);'
set @sqlstr=@sqlstr+'declare @sqlstr varchar(6000);'
if @ordertype=1
begin
set @sqlstr=@sqlstr+'set @sqlstr=''select top '+cast(@Pagesize as varchar)+' '+@fieldlist+' from (select top 100 percent * from (select top ''+cast(@rnum as varchar)+'' * from '+@tablename+' where '+@strwhere+' order by '+@orderfield+' asc) as b order by '+@orderfield+' desc) as a order by '+@orderfield+' desc '';'
end
else
begin
set @sqlstr=@sqlstr+'set @sqlstr=''select top '+cast(@Pagesize as varchar)+' '+@fieldlist+' from (select top 100 percent * from (select top ''+cast(@rnum as varchar)+'' * from '+@tablename+' where '+@strwhere+' order by '+@orderfield+' desc) as b order by '+@orderfield+' asc) as a order by '+@orderfield+' asc '';'
end
set @sqlstr=@sqlstr+'execute(@sqlstr)'
end
else --------------------------------------------------------------当查询条件为空
begin
set @sqlstr=@sqlstr+'set @rcount=(select count(*) from '+@tablename+');'
set @sqlstr=@sqlstr+'declare @rnum int;'
set @sqlstr=@sqlstr+'set @rnum=@rcount-'+cast(@pagesize as varchar)+'*('+cast(@pageindex as varchar)+'-1);'
set @sqlstr=@sqlstr+'declare @sqlstr varchar(6000);'
if @ordertype=1
begin
set @sqlstr=@sqlstr+'set @sqlstr=''select top '+cast(@Pagesize as varchar)+' '+@fieldlist+' from (select top 100 percent * from (select top ''+cast(@rnum as varchar)+'' * from '+@tablename+' order by '+@orderfield+' asc) as b order by '+@orderfield+' desc) as a order by '+@orderfield+' desc '';'
end
else
begin
set @sqlstr=@sqlstr+'set @sqlstr=''select top '+cast(@Pagesize as varchar)+' '+@fieldlist+' from (select top 100 percent * from (select top ''+cast(@rnum as varchar)+'' * from '+@tablename+' order by '+@orderfield+' desc) as b order by '+@orderfield+' asc) as a order by '+@orderfield+' asc '';'
end
set @sqlstr=@sqlstr+'execute(@sqlstr)'
end
end
--print @sqlstr
execute(@sqlstr)
GO
转载于:https://blog.51cto.com/liyujun/632110
按任意字段排序的分页存储过程相关推荐
- 支持任意排序的分页存储过程
从网上找了一个分页存储过程,在使用的过程中出现对非主键排序查询时,查不到数据,根据sql2005 的特点修改了其bug,已经添加性能测试(2008-10-27). 存储过程 IF OBJECT_ID( ...
- java动态字段排序_JAVA 列表动态增加字段显示和任意字段排序
需求是用户可以在页面管理展示的字段,并且对字段的展示顺序自定义排序,控制所有字段显示隐藏,表中有默认基础字段是不可以删除的 这边全部都是后端实现: 思路: 数据表设定一个字段专门存放动态字段,字段内容 ...
- 【PHP】 数组分页函数、根据字段排序并分页
if (!function_exists("pageByArr")) {/*** 数组分页函数 核心函数 array_slice* 用此函数之前要先将数据库里面的所有数据按一定的顺 ...
- 动软 mysql 分页_动软.NET 分页存储过程UP_GetRecordByPage
1, ------------------------------------ --用途:支持任意排序的分页存储过程 --说明: ----------------------------------- ...
- (转)大数据量分页存储过程效率测试附代码
大数据量分页存储过程效率测试附代码 在项目中,我们经常遇到或用到分页,那么在大数据量(百万级以上)下,哪种分页算法效率最优呢?我们不妨用事实说话. 测试环境 硬件:CPU 酷睿双核T5750 内存: ...
- [转]Sql Server 分页存储过程
本文转自: 版权声明:作者:jiankunking 出处:http://blog.csdn.net/jiankunking 本文版权归作者和CSDN共有,欢迎转载,但未经作者同意必须保留此段声明,且 ...
- mysql 高效分页存储过程_mysql分页存储过程
CREATE PROCEDURE 'sp_page'( in _pagecurrent int,--/*当前页*/ in _pagesize int,--/*每页的记录数*/ in _ifelse v ...
- EFCore+Mysql仓储层建设(分页、多字段排序、部分字段更新)
前沿 园子里已有挺多博文介绍了EFCore+Mysql/MSSql如何进行使用,但实际开发不会把EF层放在Web层混合起来,需要多个项目配合结构清晰的进行分层工作,本文根据个人实践经验总结将各个项目进 ...
- MongoDB 添加、查询(条件查询、排序、分页、返回指定字段)、修改、删除数据、聚合aggregate
MongoDB内部支持JavaScript语法,使用SpiderMonkey作为内部的JavaScript解释器引擎. 1.常用命令 show databases:显示数据库列表 use:切换数据库 ...
最新文章
- 2021年春季学期-信号与系统-第七次作业参考答案-第六小题
- PowerShell让系统可以执行.ps1文件
- 作文计算机使用有什么问题,关于电脑利弊的作文
- Keras【Deep Learning With Python】LSTM 循环神经网络解决Regressor回归问题
- arcgis api for flex 开发入门(二)map 的创建
- 第09课:项目实战——让你的神经网络模型越来越深
- Java受查异常和运行时异常的理解
- 题目1208:10进制 VS 2进制(进制转换以及大数保存问题)
- 画图调子图间距_好看好用的桥梁工程图,你值得拥有!
- L1-056 猜数字-PAT团体程序设计天梯赛GPLT
- 模型☀️Catia模型到Unity的转化过程
- 生成田字格模板(word)
- python暑假培训成都
- Flutter—— 仿自如APP裸眼3D效果
- 敏捷培训: 如何使培训产生共鸣?
- 浪潮服务器上RAID配置实战及RAID相关知识
- (更新时间)2021年6月4日 商城高并发秒杀系统(.NET Core版) 30-lua文件封装加载和执行
- Android 常用开源框架源码解析 系列 (九)dagger2 呆哥兔 依赖注入库
- 整除/ 与 求余% 运算
- 【SAP】查询所有用户信息并导出
热门文章
- Controller和RequestMapping
- HDU 1542 Atlantis 线段树+离散化+扫描线
- Web Application Security 网络应用程序安全 - (二)2010年网络安全威胁排行榜TOP 10...
- Spring框架中IoC(控制反转)的原理
- window中使用jedis连接虚拟机中的redis
- spark任务提交流程源码分析
- idea 本地远程debug服务器项目
- Swagger与Springboot集成restful进行接口测试
- c语言isfinite_csqrtf - [ C语言中文开发手册 ] - 在线原生手册 - php中文网
- @getmapping注解的作用_@Transactional注解失效了?你遇到的是这6种场景吧!