sql server 游标

一、遇到的问题

        实际上,也不算什么太大的问题O(∩_∩)O:我们有时候可能希望在批处理或者存储过程中直接对select结果集进行加工,这个时候,我们需要一种能够让我们逐条处理每一行记录的数据库对象。

二、游标的概念

        解决上面的问题,我们可以使用一种叫做“游标”的数据库对象。

        游标(Cursor)可以看做一种数据类型,它可以用来遍历结果集,相当于指针,或者是数组中的下标。它处理结果集的方法有以下几种:

Ø  定位到结果集的某一行

Ø  从当前结果集的位置搜索一行或一部分行

Ø  对结果集中的当前行进行数据修改

三、游标的使用方法(创建、打开、读取、关闭、删除)

【创建游标】

        和定义各种数据类型的方法有点像,但是注意,不要加“@”(实际上也有“游标类型的变量”,和“游标”的用法几乎完全相同,而且定义时使用@符号)。下面是定义游标的语句:

declare 游标名 cursor [local|global] [forward_only|scroll]
for
select查询语句

        游标分为局部游标和全局游标两种,local表示局部游标,global表示全局游标(默认值,可以省略)。当指定forward_only(默认值,可以省略)时,游标是只进的,也就是说只能从头到尾地提取记录,如果需要在行之间来回跳跃,需要指定为scroll。

【使用游标】

        只创建游标但是不使用它,就没有任何意义了。下面我们先举个最简单的例子来演示创建好游标之后的几步使用过程:

--【创建游标】
declare C1 cursor for select xingming from yiren
declare @xingming varchar(20)
--【打开游标】
open C1
--【读取游标】
fetch next from C1 into @xingming --while的特点就是要先写一次
while(@@FETCH_STATUS=0)
begin
    print '姓名:'+@xingming
    fetch next from C1 into @xingming
end
--【关闭游标】
close C1
--【删除游标】
deallocate C1

        游标的使用方法是不是和Java中的 whle(rs.next()){}很像呢?实际上rs.next()执行时就直接在结果集中向后移动一条了,如果没有到达结果集的末端,仍然会执行循环体。在这里使用游标也是一样,@@FETCH_STATUS的值为0时,游标尚未走到结尾。当它不为0了,游标就走到了结尾,将退出循环。

        fetch next from 游标名 into 变量名列表 是一种固定形式的读取游标内容的方法。当查询语句选择了多个字段的时候,读取时也需要借助这句话向多个变量赋值。于是写成变量名列表。

【全局游标和scroll游标】

        前面提到全局游标和scroll游标,下面举个例子:

if(CURSOR_STATUS('global','CURSOR_2')!=-3) deallocate CURSOR_2
declare CURSOR_2 cursor scroll --全局的scroll游标
for select xingming,nicheng,xingbie from yiren

--第一个T-SQL批开始

open CURSOR_2
declare @seq int,
@xingming varchar(20),@nicheng varchar(50),@xingbie nchar
set @seq=4
fetch absolute @seq from CURSOR_2 into @xingming,@nicheng,@xingbie
if(@@FETCH_STATUS=0)
begin
    print '第'+cast(@seq as varchar)+'个艺人是:'+@xingming
    print case @xingbie when '男' then '他' when '女' then '她' end
+'的昵称是:'+@nicheng
end
close CURSOR_2
go

--第二个T-SQL批开始

open CURSOR_2
declare @seq int,
@xingming varchar(20),@nicheng varchar(50),@xingbie nchar
set @seq=5 --分成了两个批,需要再次定义@seq
fetch absolute @seq from CURSOR_2 into @xingming,@nicheng,@xingbie
if(@@FETCH_STATUS=0)
begin
    print '第'+cast(@seq as varchar)+'个艺人是:'+@xingming
    print case @xingbie when '男' then '他' when '女' then '她' end
+'的昵称是:'+@nicheng
end
close CURSOR_2
go

--在第三个批中删除游标

deallocate CURSOR_2

        当开启了scroll选项后,fetch可以用于读next(后移)、prior(前移)、first(第一行)、last(最后一行)、absolute(以数值定位到绝对行)、relative(以数值定位到相对行)

        全局游标一旦被定义就会一直存在,所以每个批处理都能看到它。直到使用deallocate来删除它,它才会消失。CURSOR_STATUS('global','CURSOR_2')可以检查它的状态。

【游标的嵌套】

       由于大大影响系统性能,简单了解一下即可。

if(CURSOR_STATUS('global','CURSOR_3')!=-3) deallocate CURSOR_3
declare CURSOR_3 cursor for
    select yanchuid from yanchu

open CURSOR_3
declare @ycid int
fetch next from CURSOR_3
    into @ycid
while(@@FETCH_STATUS=0)
begin

    print '参加第'+cast(@ycid as varchar)+'次演出的艺人是:'

    declare CURSOR_4 cursor for
       select xingming from yiren where yirenid in
       (select yirenid from yanchuyiren where yanchuid=@ycid)
    --这句使用了子查询,实际上可以再嵌套一个游标
    declare @xingming varchar(50)
    open CURSOR_4
    fetch next from CURSOR_4 into @xingming
    while(@@FETCH_STATUS=0)
    begin
       print @xingming
       fetch next from CURSOR_4 into @xingming
    end
    close CURSOR_4
    deallocate CURSOR_4

    fetch next from CURSOR_3
       into @ycid
    print ''
end
close CURSOR_3
deallocate CURSOR_3

【游标变量】

        游标变量是真正的把游标当做数据类型来使用的一种方法,游标变量和游标对象的区别就在于是否有@。创建游标变量的时候,首先declare @游标变量名 cursor,然后set @游标变量名=cursorfor select语句。

declare @c1 CURSOR
set @c1=cursor for select xingming from yiren
open @c1
declare @xingming varchar(50)
fetch next from @c1 into @xingming
print @xingming
close @c1
deallocate @c1

四、游标的注意事项

【游标的缺点】

        使用游标会把结果集一条条取出来处理,增加了服务器的负担,再者使用游标的效率远远没有使用默认结果集的效率高。所以,能不用游标就尽量不要用。

【游标的补充说明】

        当我们刚刚打开一个游标的时候,它并不指向第一条记录,而是指向第一条记录的前边。我们可以拿书做比喻,游标不仅仅可以指向记录集中的记录(书内容的每一页),也可以指向记录集外部没有记录的地方(书的封面和封底)。

        @@fetch_status有3种取值:0表示fetch 正常执行、-1表示fetch超出了结果集、-2表示fetch所指向的行已经不存在了。

五、修改分页查询存储过程,使用游标

        将第一个分支修改成如下代码:

if @currentpage >1
begin
    if @currentpage>@totalpages
    begin
       set @currentpage = @totalpages
    end
    declare    @start int,@count int
    set @count = 0
    set @start = @currentpage*@pagesize+1
    set @sql='declare cursor_1 cursor scroll for select * from '
    +@tablename+' order by '+@idname
    exec(@sql)
    open cursor_1
    fetch relative @start,@pagesize from cursor_1
    while @@fetch_status=0
    begin
       set @count = @count+1
       fetch next from cursor_1
       if @count=@pagesize-1
           break
    end
    close cursor_1
    deallocate cursor_1
end
并去掉原来go前面的
exec(@sql)

即可。如果不去掉这句,会在存储过程的最后额外再执行一次这句话,从而错误地再次生成@cursor_1游标。

原文地址:点击打开链接

时间: 2024-12-10 08:07:52

sql server 游标的相关文章

SQL Server游标实例演示不得不看

以下的文章主要描述的是SQL Server游标实例,假如你在实际操作中遇SQL Server游标实例,但是你却不知道对其如何正确应用,那么以下的文章对你而言一定是良师益友,希望会给你带来一些帮助在此方面. SQL Server游标实例: Declare MyCusror Cursor Scroll     For Select * From Master_Goods Order By GoodsID     Open MyCursor     Fetch next From MyCursor  

SQL Server 游标语句 声明/打开/循环实例_MsSql

SQL Server游标语句使用方法: 复制代码 代码如下: --声明一个游标 DECLARE MyCursor CURSOR FOR SELECT TOP 5 FBookName,FBookCoding FROM TBookInfo//定义一个叫MyCursor的游标,存放for select 后的数据 --打开一个游标 OPEN MyCursor//即打开这个数据集 --循环一个游标 DECLARE @BookName nvarchar(2000),@BookCoding nvarchar(

SQL Server 游标语句 声明/打开/循环实例

SQL Server游标语句使用方法: 复制代码 代码如下: --声明一个游标 DECLARE MyCursor CURSOR FOR SELECT TOP 5 FBookName,FBookCoding FROM TBookInfo//定义一个叫MyCursor的游标,存放for select 后的数据 --打开一个游标 OPEN MyCursor//即打开这个数据集 --循环一个游标 DECLARE @BookName nvarchar(2000),@BookCoding nvarchar(

SQL Server游标运用:查看一个数据库所有表大小信息

一.背景 在性能调优或者需要了解某数据库表信息的时候,最直观的方式就是罗列出这个数据所有表的信息,这些信息包括:表的记录数.数据记录占用空间.索引占用空间.未使用的空间等(如Figure1所示),有了这些信息你可以简单的判断这个数据库来自数据上的压力可能是某个表造成的.因为表数据越大,对数据库性能的影响越大. 要实现某个数据库所有表的信息,可以通过游标的形式获取相应的数据,下图Figure1返回某数据库中所有表的信息: (Figure1:某数据库所有表信息) 也许你并不满足于Figure1的信息

SQL Server 游标使用

  游标概念 数据库操作中我们常常会遇到这样情况,即从某一结果集中逐一地读取一条记录.那么如何解决这种问题呢?游标为我们提供了一种极为优秀的解决方案. 游标(cursor)是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果. 每个游标区都有一个名字.用户可以用SQL语句逐一从游标中获取记录,并赋给主变量,交由主语言进一步处理.游标提供了一种对从表中检索出的数据进行操作的灵活手段,就本质而言,游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制. 游标总是与一条SQL 查询

MS SQL Server游标(CURSOR)的学习使用

说实的,使用MS SQL Server这样久,游标一直没有使用过.以前实现相似的功能,都是使用WHILE循环加临时表来实现.刚才有参考网上示例练习写了一下.了解到游标概念与语法. 下面代码示例中, 先是宣告你在游标中需使用变量,也就是临时存储处理字段的数据. 2. 宣告一个游标,并SELECT需要处理的数据集. 3. 打开游标(#8行代码). 4. 从游标中拿来FETCH NEXT 数据给变量赋值. 5. 循环@@FETCH_STATUS = 0条件. 6. 在循环块,可以处理第一笔的记录逻辑了

利用 Sql Server 游标删除重复记录

这段时间因项目需要导入原有的数据到新库中,遭遇了数据重复的问题,需删除重复的数据.我采用游标的方法解决此问题. Sql 语句如下以免忘记. 代码 --删除重复数据,只保留记录号最大的declare mycursor cursor     for    select addinip from testdb group by addinip having count(addinip)>1open mycursordeclare @ip sysnamefetch next from mycursor 

SQL Server游标的使用

原文地址:http://www.cnblogs.com/moss_tan_jun/archive/2011/11/26/2263988.html 游标是邪恶的!        在关系数据库中,我们对于查询的思考是面向集合的.而游标打破了这一规则,游标使得我们思考方式变为逐行进行.对于类C的开发人员来着,这样的思考方式会更加舒服.        正常面向集合的思维方式是:               而对于游标来说:              这也是为什么游标是邪恶的,它会使开发人员变懒,懒得去想

SQL Server游标的使用/关闭/释放/优化小结_MsSql

游标是邪恶的! 在关系数据库中,我们对于查询的思考是面向集合的.而游标打破了这一规则,游标使得我们思考方式变为逐行进行.对于类C的开发人员来着,这样的思考方式会更加舒服. 正常面向集合的思维方式是: 而对于游标来说: 这也是为什么游标是邪恶的,它会使开发人员变懒,懒得去想用面向集合的查询方式实现某些功能. 同样的,在性能上,游标会吃更多的内存,减少可用的并发,占用宽带,锁定资源,当然还有更多的代码量-- 从游标对数据库的读取方式来说,不难看出游标为什么占用更多的资源,打个比方:     当你从A