视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
sql分页查询几种写法
2020-11-09 07:03:11 责编:小采
文档


关于SQL语句分页,网上也有很多,我贴一部分过来,并且总结自己已知的分页到下面,方便日后查阅

1.创建测试环境,(插入100万条数据大概耗时5分钟)。

create database DBTest
use DBTest
 
--创建测试表
create table pagetest
(
id int identity(1,1) not null,
col01 int null,
col02 nvarchar(50) null,
col03 datetime null
)
 
--1万记录集
declare @i int
set @i=0
while(@i<10000)
begin
 insert into pagetest select cast(floor(rand()*10000) as int),left(newid(),10),getdate()
 set @i=@i+1
end

2.几种典型的分页sql,下面例子是每页50条,198*50=9900,取第199页数据。

--写法1,not in/top

select top 50 * from pagetest
where id not in (select top 9900 id from pagetest order by id)
order by id

--写法2,not exists

select top 50 * from pagetest
where not exists
(select 1 from (select top 9900 id from pagetest order by id)a where a.id=pagetest.id)
order by id

--写法3,max/top

select top 50 * from pagetest
where id>(select max(id) from (select top 9900 id from pagetest order by id)a)
order by id

 --写法4,row_number()

select top 50 * from
(select row_number()over(order by id)rownumber,* from pagetest)a
where rownumber>9900
 
select * from
(select row_number()over(order by id)rownumber,* from pagetest)a
where rownumber>9900 and rownumber<9951
 
select * from
(select row_number()over(order by id)rownumber,* from pagetest)a
where rownumber between 9901 and 9950

--写法5,在csdn上一帖子看到的,row_number() 变体,不基于已有字段产生记录序号,先按条件筛选以及排好序,再在结果集上给一常量列用于产生记录序号

select *
from (
 select row_number()over(order by tempColumn)rownumber,*
 from (select top 9950 tempColumn=0,* from pagetest where 1=1 order by id)a
)b
where rownumber>9900

3.分别在1万,10万(取1990页),100(取19900页)记录集下测试。

测试sql:

declare @begin_date datetime
declare @end_date datetime
select @begin_date = getdate()
<.....YOUR CODE.....>
select @end_date = getdate()
select datediff(ms,@begin_date,@end_date) as '毫秒'

1万:基本感觉不到差异。

10万:

4.结论:

1.max/top,ROW_NUMBER()都是比较不错的分页方法。相比ROW_NUMBER()只支持sql2005及以上版本,max/top有更好的可移植性,能同时适用于sql2000,access。

2.not exists感觉是要比not in效率高一点点。

3.ROW_NUMBER()的3种不同写法效率看起来差不多。

4.ROW_NUMBER() 的变体基于我这个测试效率实在不好。原帖在这里 http://topic.csdn.net/u/20100617/04/80d1bd99-2e1c-4083-ad87-72bf706cb536.html

PS.上面的分页排序都是基于自增字段id。测试环境还提供了int,nvarchar,datetime类型字段,也可以试试。不过对于非主键没索引的大数据量排序效率应该是很不理想的。

5.简单将ROWNUMBER,max/top的方式封装到存储过程。

ROWNUMBER():

ALTER PROCEDURE [dbo].[Proc_SqlPageByRownumber]
(
 @tbName VARCHAR(255), --表名
 @tbGetFields VARCHAR(1000)= '*',--返回字段
 @OrderfldName VARCHAR(255), --排序的字段名
 @PageSize INT=20, --页尺寸
 @PageIndex INT=1, --页码
 @OrderType bit = 0, --0升序,非0降序
 @strWhere VARCHAR(1000)='', --查询条件
 --@TotalCount INT OUTPUT --返回总记录数
)
AS
-- =============================================
-- Author: allen (liyuxin)
-- Create date: 2012-03-30
-- Description: 分页存储过程(支持多表连接查询)
-- Modify [1]: 2012-03-30
-- =============================================
BEGIN
 DECLARE @strSql VARCHAR(5000) --主语句
 DECLARE @strSqlCount NVARCHAR(500)--查询记录总数主语句
 DECLARE @strOrder VARCHAR(300) -- 排序类型

 --------------总记录数---------------
 IF ISNULL(@strWhere,'') <>'' 
 SET @strSqlCount='Select @TotalCout=count(*) from ' + @tbName + ' where 1=1 '+ @strWhere
 ELSE SET @strSqlCount='Select @TotalCout=count(*) from ' + @tbName
 
 --exec sp_executesql @strSqlCount,N'@TotalCout int output',@TotalCount output
 --------------分页------------
 IF @PageIndex <= 0 SET @PageIndex = 1

 IF(@OrderType<>0) SET @strOrder=' ORDER BY '+@OrderfldName+' DESC '
 ELSE SET @strOrder=' ORDER BY '+@OrderfldName+' ASC '

 SET @strSql='SELECT * FROM 
 (SELECT ROW_NUMBER() OVER('+@strOrder+') RowNo,'+ @tbGetFields+' FROM ' + @tbName + ' WHERE 1=1 ' + @strWhere+' ) tb 
 WHERE tb.RowNo BETWEEN '+str((@PageIndex-1)*@PageSize+1)+' AND ' +str(@PageIndex*@PageSize)

 exec(@strSql)
 SELECT @TotalCount
END

  

public static SqlParameter MakeInParam(string ParamName, SqlDbType DbType, Int32 Size, object Value)
 {
 return MakeParam(ParamName, DbType,Size, ParameterDirection.Input, Value);
 }
 public static SqlParameter MakeOutParam(string ParamName, SqlDbType DbType)
 {
 return MakeParam(ParamName, DbType, 0, ParameterDirection.Output, null);
 }
 public static SqlParameter MakeParam(string ParamName, SqlDbType DbType, Int32 Size, ParameterDirection Direction, object Value)
 {
 SqlParameter param;
 if (Size > 0)
 param = new SqlParameter(ParamName, DbType, Size);
 else
 param = new SqlParameter(ParamName, DbType);
 param.Direction = Direction;
 if (!(Direction == ParameterDirection.Output && Value == null))
 param.Value = Value;
 return param;
 }
 /// <summary>
 /// 分页获取数据列表及总行数
 /// </summary>
 /// <param name="tbName">表名</param>
 /// <param name="tbGetFields">返回字段</param>
 /// <param name="OrderFldName">排序的字段名</param>
 /// <param name="PageSize">页尺寸</param>
 /// <param name="PageIndex">页码</param>
 /// <param name="OrderType">false升序,true降序</param>
 /// <param name="strWhere">查询条件</param>
 public static DataSet GetPageList(string tbName, string tbGetFields, string OrderFldName, int PageSize, int PageIndex, string strWhere)
 {
 SqlParameter[] parameters = {
 MakeInParam("@tbName",SqlDbType.VarChar,255,tbName),
 MakeInParam("@tbGetFields",SqlDbType.VarChar,1000,tbGetFields),
 MakeInParam("@OrderfldName",SqlDbType.VarChar,255,OrderFldName),
 MakeInParam("@PageSize",SqlDbType.Int,0,PageSize),
 MakeInParam("@PageIndex",SqlDbType.Int,0,PageIndex),
 MakeInParam("@OrderType",SqlDbType.Bit,0,OrderType),
 MakeInParam("@strWhere",SqlDbType.VarChar,1000,strWhere),
 // MakeOutParam("@TotalCount",SqlDbType.Int)
 };
 return RunProcedure("Proc_SqlPageByRownumber", parameters, "ds");
 }

调用:

public DataTable GetList(string tbName, string tbGetFields, string OrderFldName, int PageSize, int PageIndex, string strWhere, ref int TotalCount)
 {
 DataSet ds = dal.GetList(tbName, tbGetFields, OrderFldName, PageSize, PageIndex, strWhere);
 TotalCount = Convert.ToInt32(ds.Tables[1].Rows[0][0]);
 return ds.Tables[0];
 }

注意:多表连接时需注意的地方

1.必填项:tbName,OrderfldName,tbGetFields

2.实例:

tbName =“UserInfo u INNER JOIN Department d ON u.DepID=d.ID”
 tbGetFields=“u.ID AS UserID,u.Name,u.Sex,d.ID AS DepID,d.DefName”
 OrderfldName=“u.ID,ASC|u.Name,DESC” (格式:Name,ASC|ID,DESC)
 strWhere:每个条件前必须添加 AND (例如:AND UserInfo.DepID=1 )

Max/top:(简单写了下,需要满足主键字段名称就是"id")

create proc [dbo].[spSqlPageByMaxTop]
@tbName varchar(255), --表名
@tbFields varchar(1000), --返回字段
@PageSize int, --页尺寸
@PageIndex int, --页码
@strWhere varchar(1000), --查询条件
@StrOrder varchar(255), --排序条件
@Total int output --返回总记录数
as
declare @strSql varchar(5000) --主语句
declare @strSqlCount nvarchar(500)--查询记录总数主语句

--------------总记录数---------------
if @strWhere !=''
begin
set @strSqlCount='Select @TotalCout=count(*) from ' + @tbName + ' where '+ @strWhere
end
else
begin
set @strSqlCount='Select @TotalCout=count(*) from ' + @tbName
end
--------------分页------------
if @PageIndex <= 0
begin
 set @PageIndex = 1
end

set @strSql='select top '+str(@PageSize)+' * from ' + @tbName + '
where id>(select max(id) from (select top '+str((@PageIndex-1)*@PageSize)+' id from ' + @tbName + ''+@strOrder+')a)
'+@strOrder+''

exec sp_executesql @strSqlCount,N'@TotalCout int output',@Total output
exec(@strSql)

园子里搜到Max/top这么一个版本,看起来很强大,http://www.cnblogs.com/hertcloud/archive/2005/12/21/301327.html

调用:

declare @count int
--exec [dbo].[spSqlPageByRownumber]'pagetest','*',50,20,'','order by id asc',@count output
exec [dbo].[spSqlPageByMaxTop]'pagetest','*',50,20,'','order by id asc',@count output
select @count

下载本文
显示全文
专题