zoukankan      html  css  js  c++  java
  • 查询分页的几种Sql写法

    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():

    复制代码
    复制代码
     1 ALTER PROCEDURE [dbo].[Proc_SqlPageByRownumber]
    2 (
    3 @tbName VARCHAR(255), --表名
    4 @tbGetFields VARCHAR(1000)= '*',--返回字段
    5 @OrderfldName VARCHAR(255), --排序的字段名
    6 @PageSize INT=20, --页尺寸
    7 @PageIndex INT=1, --页码
    8 @OrderType bit = 0, --0升序,非0降序
    9 @strWhere VARCHAR(1000)='', --查询条件
    10 --@TotalCount INT OUTPUT --返回总记录数
    11 )
    12 AS
    13 -- =============================================
    14 -- Author: allen (liyuxin)
    15 -- Create date: 2012-03-30
    16 -- Description: 分页存储过程(支持多表连接查询)
    17 -- Modify [1]: 2012-03-30
    18 -- =============================================
    19 BEGIN
    20 DECLARE @strSql VARCHAR(5000) --主语句
    21 DECLARE @strSqlCount NVARCHAR(500)--查询记录总数主语句
    22 DECLARE @strOrder VARCHAR(300) -- 排序类型
    23
    24 --------------总记录数---------------
    25 IF ISNULL(@strWhere,'') <>''
    26 SET @strSqlCount='Select @TotalCout=count(*) from ' + @tbName + ' where 1=1 '+ @strWhere
    27 ELSE SET @strSqlCount='Select @TotalCout=count(*) from ' + @tbName
    28
    29 --exec sp_executesql @strSqlCount,N'@TotalCout int output',@TotalCount output
    30 --------------分页------------
    31 IF @PageIndex <= 0 SET @PageIndex = 1
    32
    33 IF(@OrderType<>0) SET @strOrder=' ORDER BY '+@OrderfldName+' DESC '
    34 ELSE SET @strOrder=' ORDER BY '+@OrderfldName+' ASC '
    35
    36 SET @strSql='SELECT * FROM
    37 (SELECT ROW_NUMBER() OVER('+@strOrder+') RowNo,'+ @tbGetFields+' FROM ' + @tbName + ' WHERE 1=1 ' + @strWhere+' ) tb
    38 WHERE tb.RowNo BETWEEN '+str((@PageIndex-1)*@PageSize+1)+' AND ' +str(@PageIndex*@PageSize)
    39
    40 exec(@strSql)
    41 SELECT @TotalCount
    42 END
    复制代码
    复制代码

    C#

    复制代码
    复制代码
     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
  • 相关阅读:
    Working with macro signatures
    Reset and Clear Recent Items and Frequent Places in Windows 10
    git分支演示
    The current .NET SDK does not support targeting .NET Core 2.1. Either target .NET Core 2.0 or lower, or use a version of the .NET SDK that supports .NET Core 2.1.
    Build website project by roslyn through devenv.com
    Configure environment variables for different tools in jenkins
    NUnit Console Command Line
    Code Coverage and Unit Test in SonarQube
    头脑王者 物理化学生物
    头脑王者 常识,饮食
  • 原文地址:https://www.cnblogs.com/accumulater/p/6101726.html
Copyright © 2011-2022 走看看