李洪根ID:lihonggen0
171602次访问,排名425好友4人,关注者12
MS MVP 软件开发专家
lihonggen0的文章
原创 47 篇
翻译 0 篇
转载 0 篇
评论 171 篇
lihonggen的公告
贴子以"现状"提供且没有任何担保也没有授予任何权利。
转载请注明原文章出处!
最近评论
jdmei520:建立数据库的最好方法:执行Sql语句附加数据库。

EXEC sp_attach_db @dbname = N'pubs',
@filename1 = N'c:\Program Files\Microsoft SQL Server\MSSQL\Data\pubs.mdf',
@filename2 = N'c:\Program Files……
cenyar:我想问一下如果在C#中,要达到密码以*显示,那代码咋写呢?急用
QQ:285738534
rexfa:微软东西很好玩,用它赚钱糊口就不是很好玩了。
go2newlife:旧的还没熟悉,新的又来了,放弃旧的学新的,不知道这样的循环,什么时候才能适应,吃快餐也能吃出营养来吗?其实学习的过程,还是多积累点基础性的,不大会变化的东西,像SQL,不管你数据库产品怎么变,我都能适应,像VB语法,改进了我也能适应去开发,而对于类库,关注的是它的设计,好多好多,自己也没底.不知道有谁能指导一下,我的QQ829098
ZengYongChun:老大,强!
文章分类
收藏
    相册
    SQL Server 2005
    软件截图
    我的照片
    .NET技术站点
    codeproject.com
    微软官方站点asp.net
    微软官方站点Gotdotnet
    微软官方站点windowsforms
    我的个人链接
    CSDN文档中心
    在微软的专栏
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 SQL Server 存储过程的分页方案比拼收藏

    新一篇: 在VB6和VB.net中设置桌面墙纸 | 旧一篇: SQL Server中发送邮件的新方式

    SQL Server 存储过程的分页,这个问题已经讨论过几年了,很多朋友在问我,所以在此发表一下我的观点
    建立表:

    CREATE TABLE [TestTable] (
     [ID] [int] IDENTITY (1, 1) NOT NULL ,
     [FirstName] [nvarchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
     [LastName] [nvarchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
     [Country] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
     [Note] [nvarchar] (2000) COLLATE Chinese_PRC_CI_AS NULL
    ) ON [PRIMARY]
    GO

     

    插入数据:(2万条,用更多的数据测试会明显一些)
    SET IDENTITY_INSERT TestTable ON

    declare @i int
    set @i=1
    while @i<=20000
    begin
        insert into TestTable([id], FirstName, LastName, Country,Note) values(@i, 'FirstName_XXX','LastName_XXX','Country_XXX','Note_XXX')
        set @i=@i+1
    end

    SET IDENTITY_INSERT TestTable OFF

     

    -------------------------------------

    分页方案一:(利用Not In和SELECT TOP分页)
    语句形式:
    SELECT TOP 10 *
    FROM TestTable
    WHERE (ID NOT IN
              (SELECT TOP 20 id
             FROM TestTable
             ORDER BY id))
    ORDER BY ID


    SELECT TOP 页大小 *
    FROM TestTable
    WHERE (ID NOT IN
              (SELECT TOP 页大小*页数 id
             FROM 表
             ORDER BY id))
    ORDER BY ID

    -------------------------------------

    分页方案二:(利用ID大于多少和SELECT TOP分页)
    语句形式:
    SELECT TOP 10 *
    FROM TestTable
    WHERE (ID >
              (SELECT MAX(id)
             FROM (SELECT TOP 20 id
                     FROM TestTable
                     ORDER BY id) AS T))
    ORDER BY ID


    SELECT TOP 页大小 *
    FROM TestTable
    WHERE (ID >
              (SELECT MAX(id)
             FROM (SELECT TOP 页大小*页数 id
                     FROM 表
                     ORDER BY id) AS T))
    ORDER BY ID


    -------------------------------------

    分页方案三:(利用SQL的游标存储过程分页)
    create  procedure XiaoZhengGe
    @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

    其它的方案:如果没有主键,可以用临时表,也可以用方案三做,但是效率会低。
    建议优化的时候,加上主键和索引,查询效率会提高。

    通过SQL 查询分析器,显示比较:我的结论是:
    分页方案二:(利用ID大于多少和SELECT TOP分页)效率最高,需要拼接SQL语句
    分页方案一:(利用Not In和SELECT TOP分页)   效率次之,需要拼接SQL语句
    分页方案三:(利用SQL的游标存储过程分页)    效率最差,但是最为通用

    在实际情况中,要具体分析。


    更多的讨论见:
    http://community.csdn.net/Expert/topic/3292/3292678.xml?temp=.1621515

    发表于 @ 2004年09月14日 01:05:00|评论(loading...)|编辑

    新一篇: 在VB6和VB.net中设置桌面墙纸 | 旧一篇: SQL Server中发送邮件的新方式

    评论

    #hubinasm 发表于2004-11-21 23:51:00  IP:
    TrackBack来自《关于数据库分页》

    Ping Back来自:blog.csdn.net
    #3doyang 发表于2005-02-15 19:14:00  IP:
    TrackBack来自《ASP.NET分页的处理方式》

    Ping Back来自:blog.csdn.net
    #曾登高 发表于2005-03-28 01:11:00  IP:
    TrackBack来自《近日关注:系统性能提升之道--内存镜像表》

    Ping Back来自:blog.csdn.net
    #ξσ Dicky σξ 发表于2005-06-18 10:36:00  IP:
    TrackBack来自《SQL Server 存储过程的分页方案比拼》

    Ping Back来自:blog.csdn.net
    #leeight 发表于2005-07-12 10:38:00  IP:
    TrackBack来自《关于存储过程实现分页的技术》

    Ping Back来自:blog.csdn.net
    #squirrel_sc 发表于2004-09-28 20:38:00  IP: 61.49.220.*
    能否给出具体的测试结果数据呢?谢谢~
    #QQ'Richer 发表于2004-10-29 10:12:00  IP: 219.239.44.*
    好,总算找到这篇文章了,谢谢洪根兄
    #SUN 发表于2004-11-09 10:49:00  IP: 61.233.144.*
    declare @pagesize int
    set @pagesize = 10
    select top @pagesize * from album
    order by picid

    这样怎么不对啊?
    老大!
    select top 10 * from album
    order by picid
    又可以 为什么呢?
    那我怎么写存储过程啊!
    #SUN 发表于2004-11-09 11:06:00  IP: 61.233.144.*
    那我 不是 不能写成 存储过程?
    只有写成 SQL语句放在页面上?
    这样不是会降低性能?
    #sunny 发表于2004-12-02 22:25:00  IP: 61.149.250.*
    第二种办法,如果按照主键排序可以。

    不然的话不行。
    #菩提树 发表于2004-12-08 18:06:00  IP: 219.133.133.*
    很多情况下,我们可能不能按主键来排序并分页,比如,你可能需要按工资高低给20万条记录分页及排序,那你肯定只能用临时表或者游标了,游标我不熟,临时表倒是可以达到目的,可是效率不好呀
    ALTER PROCEDURE dbo.GetPageRecord
    (
    @tblName varchar(255), -- 表名
    @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 #tmp
    (
    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 #tmp (oldid) '+@sqlstr
    execute(@sqlstr)
    set @sqlstr='SELECT TableA.* FROM '+@tblname+' TableA (nolock), #tmp T WHERE T.oldid = T
    #菩提树 发表于2004-12-08 18:06:00  IP: 219.133.133.*
    ALTER PROCEDURE dbo.GetPageRecord
    (
    @tblName varchar(255), -- 表名
    @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 #tmp
    (
    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 #tmp (oldid) '+@sqlstr
    execute(@sqlstr)
    set @sqlstr='SELECT TableA.* FROM '+@tblname+' TableA (nolock), #tmp T WHERE T.oldid = TableA.'+@keyfield+' AND T.RecNo > '+ cast(@PageLowerBound as varchar)+' AND T.RecNo < '
    #Nill 发表于2005-03-05 01:44:00  IP: 219.128.247.*
    我改了下方案2

    declare @pagesize int
    declare @pagenum int
    set @pagenum=3---第几页
    set @pagesize=20 ----每页显示条目数

    declare @t0 varchar(10)
    declare @t1 varchar(10)

    set @t0=cast(@pagesize as varchar(10))
    set @t1=cast(@pagesize*(@pagenum-1) as varchar(10))
    --加了个判断是否是第一页。
    if @pagenum<>1
    exec('SELECT TOP '+@t0+ ' * FROM DV_board WHERE (boardid >(SELECT MAX(boardid) FROM (SELECT TOP '+@t1+ ' boardid FROM DV_board ORDER BY boardid) AS T)) ORDER BY boardID')
    else
    exec('SELECT TOP '+@t0+ ' * FROM DV_board')
    #我是好猫 发表于2005-03-29 20:49:00  IP: 218.58.242.*
    什么时候,盖子能推出个 适合分页(类似 mysql 的 LIMIT )的 新mssql版本啊 。。。。
    #九命鸟 发表于2005-04-20 17:10:00  IP: 210.22.100.*
    这样分页的方例都不是很通用,可以考虑用Rowcount的方法,参数@table, @fields, @filter, @orderby, @groupby, @pagenumber, @pagesize,在SP中形成SQL语句。
    #随身影子 发表于2005-04-22 12:48:00  IP: 219.137.167.*
    如果输出按字段AA排序,并且 AA 是索引的话,用游标是最高效率的。用游标分两次分别取到Begin和End点的AA的值就可以搞定。
    #王者归来 发表于2005-06-01 22:54:00  IP: 61.186.252.*
    两个问题:1.用方法2,如何选择第一页的数据,pagesize和pagecount分别怎么传? 2.如何实现主从表数据的分页?
    #王者归来 发表于2005-06-01 22:57:00  IP: 61.186.252.*
    To 九命鸟:老兄说的这种方法哪里可以找到参考?
    #小灰 发表于2005-07-21 20:59:00  IP: 61.186.252.*
    看看这个效率如何?怎么改进?
    CREATE proc page
    @RecordCount int output,
    @QueryStr nvarchar(100)='table1',--表名、视图名、查询语句
    @PageSize int=20, --每页的大小(行数)
    @PageCurrent int=2, --要显示的页 从0开始
    @FdShow nvarchar (1000)='*', --要显示的字段列表
    @IdentityStr nvarchar (100)='id', --主键
    @WhereStr nvarchar (200)='1=1',
    @FdOrder nvarchar(100)='desc' --排序 只能取desc或者asc
    as
    declare
    @sql nvarchar(2000)
    set @sql = ''
    if @WhereStr = ''
    set @WhereStr = '1=1'

    if @PageCurrent = 0 begin
    set @sql = 'select top ' + cast(@PageSize as nvarchar(3)) + ' ' + @FdShow + ' from ' + @QueryStr + ' where ' + @WhereStr + ' order by ' + @IdentityStr + ' ' + @FdOrder
    end

    else begin
    if upper(@FdOrder) = 'DESC' begin
    set @sql = 'select top ' + cast(@PageSize as nvarchar(3)) + ' ' + @FdShow + ' from ' + @QueryStr + ' where ' + @WhereStr + ' and ' + @IdentityStr + '< ( select min(' + @IdentityStr + ') from (select top ' + cast(@PageSize*@PageCurrent as nvarchar(10)) + ' ' + @IdentityStr + ' from ' + @QueryStr + ' where ' + @WhereStr + ' order by ' + @IdentityStr + ' desc) as t) order by ' + @IdentityStr + ' desc'
    end
    else begin
    set @sql = 'select top ' + cast(@PageSize as nvarchar(3)) + ' ' + @FdShow + ' from ' + @QueryStr + ' where ' + @WhereStr + ' and ' + @IdentityStr + '> ( select max(' + @IdentityStr + ') from (select top ' + cast(@PageSize*@PageCurrent as nvarchar(10)) + ' ' + @IdentityStr + ' from ' + @QueryStr + ' whe
    #.., 发表于2005-08-15 03:27:00  IP: 61.186.252.*
    愚以为前两种方法只对主键字段的排序有效。
    ID NAME TYPEID
    1 aaa 1
    2 bbb 2
    3 ccc 3
    4 ddd 3
    5 eee 4
    6 fff 5

    例如有如上6条数据,ID为主键,TYPEID为外部键(索引)。
    如果使用ID排序,则可得正确结果。
    但是如果使用TYPEID排序的话,每页显示3条数据,要显示第2页。则两种方法都只能显示2条记录,而实际应该是3条。

    第3种方法,由于在下对sql server的cursor不熟悉,所以不清楚结果。
    #cnatang 发表于2005-09-13 15:04:00  IP: 211.100.21.*
    是啊。要实现一个完美的分页好象不可能??
    用方法2 ,我现在就碰到了 order by 非主键里的问题!
    搞了一晚上,始终没有搞掂。楼主有什么好的解决办法?
    #zxub 发表于2005-10-13 22:21:00  IP: 211.100.21.*
      order by非主键的话,就用主键字段+排序字段,我就不信不能排,我做C#分页插件的时候就是这么做的,没问题的。
    #网教中国 发表于2005-12-08 10:09:00  IP: 222.79.23.*
    不错...
    #oracle 发表于2006-01-05 10:31:00  IP: 61.154.121.*
    都不好,大多数情况下不会用主键来排序,再说拼接sql这样索引就失效了,可能从效率最高掉到效率最低
    #tkdchen 发表于2006-07-09 21:32:00  IP: 221.220.164.*
    谢谢。正需要这方面的SQL分页的指导。学习……
    #a 发表于2006-08-02 11:11:00  IP: 59.42.216.*
    i don't know
    #weiweichen 发表于2007-06-02 12:05:39  IP: 59.42.27.*
    如果没有自动增长列怎么分页啊?
    #Musicflys 发表于2007-11-15 22:27:29  IP: 58.38.241.*
    拜托,看清楚第二种方法,max至少要有一条记录吧.因此这种方法永远取不到第一条,你可以试试看.
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © lihonggen