T-SQL游标学习总结

T-SQL查询进阶-10分钟理解游标

http://www.cnblogs.com/CareySon/archive/2011/11/01/2231381.html
概述

       在关系数据库中,我们对于查询的思考是面向集合的。而游标打破了这一规则,游标使得我们思考方式变为逐行进行.对于类C的开发人员来着,这样的思考方式会更加舒服。

       正常面向集合的思维方式是:

       2

       而对于游标来说:

       3

      这也是为什么游标是邪恶的,它会使开发人员变懒,懒得去想用面向集合的查询方式实现某些功能.
      同样的,在性能上,游标会吃更多的内存,减少可用的并发,占用宽带,锁定资源,当然还有更多的代码量……
      从游标对数据库的读取方式来说,不难看出游标为什么占用更多的资源,打个比方:

          1

      当你从ATM取钱的时候,是一次取1000效率更高呢,还是取10次100?
既然游标这么“邪恶”,为什么还要学习游标

      我个人认为存在既是合理.归结来说,学习游标原因我归纳为以下2点
    1.现存系统有一些游标,我们查询必须通过游标来实现
    2.作为一个备用方式,当我们穷尽了while循环,子查询,临时表,表变量,自建函数或其他方式扔来无法实现某些查询的时候,使用游标实现.

T-SQL中游标的生命周期以及实现
    在T-SQL中,游标的生命周期由5部分组成

1.定义一个游标
     在T-SQL中,定义一个游标可以是非常简单,也可以相对复杂,取决于游标的参数.而游标的参数设置取决于你对游标原理的了解程度.
     游标其实可以理解成一个定义在特定数据集上的指针,我们可以控制这个指针遍历数据集,或者仅仅是指向特定的行,所以游标是定义在以Select开始的数据集上的:

     4

     T-SQL中的游标定义在MSDN中如下:
DECLARE cursor_name CURSOR [ LOCAL | GLOBAL ] 
     [ FORWARD_ONLY | SCROLL ] 
     [ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ] 
     [ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ] 
     [ TYPE_WARNING ] 
     FOR select_statement 
     [ FOR UPDATE [ OF column_name [ ,...n ] ] ]
[;]
    
   看起来很让人头痛是吧.下面仔细讲一下如何定义游标:
   游标分为游标类型和游标变量,对于游标变量来说,遵循T-SQL变量的定义方法(啥,不知道T-SQL变量定义的规则?参考我前面的博文).游标变量支持两种方式赋值,定义时赋值和先定义后赋值,定义游标变量像定义其他局部变量一样,在游标前加”@”,注意,如果定义全局的游标,只支持定义时直接赋值,并且不能在游标名称前面加“@”,两种定义方式如下:

    5

    下面我们来看游标定义的参数:

     LOCAL和GLOBAL二选一
     LOCAL意味着游标的生存周期只在批处理或函数或存储过程中可见,而GLOBAL意味着游标对于特定连接作为上下文,全局内有效,例如:

     6

     如果不指定游标作用域,默认作用域为GLOBAL

     FORWARD_ONLY 和 SCROLL 二选一

     FORWARD_ONLY意味着游标只能从数据集开始向数据集结束的方向读取,FETCH NEXT是唯一的选项,而SCROLL支持游标在定义的数据集中向任何方向,或任何位置移动,如下图:

     7

    STATIC  KEYSET  DYNAMIC  和 FAST_FORWARD 四选一
    这四个关键字是游标所在数据集所反应的表内数据和游标读取出的数据的关系
    STATIC意味着,当游标被建立时,将会创建FOR后面的SELECT语句所包含数据集的副本存入tempdb数据库中,任何对于底层表内数据的更改不会影响到游标的内容.
    DYNAMIC是和STATIC完全相反的选项,当底层数据库更改时,游标的内容也随之得到反映,在下一次fetch中,数据内容会随之改变
    KEYSET可以理解为介于STATIC和DYNAMIC的折中方案。将游标所在结果集的唯一能确定每一行的主键存入tempdb,当结果集中任何行改变或者删除时,@@FETCH_STATUS会为-2,KEYSET无法探测新加入的数据

    FAST_FORWARD可以理解成FORWARD_ONLY的优化版本.FORWARD_ONLY执行的是静态计划,而FAST_FORWARD是根据情况进行选择采用动态计划还是静态计划,大多数情况下FAST_FORWARD要比FORWARD_ONLY性能略好.

    READ_ONLY  SCROLL_LOCKS  OPTIMISTIC 三选一 
    READ_ONLY意味着声明的游标只能读取数据,游标不能做任何更新操作

    SCROLL_LOCKS是另一种极端,将读入游标的所有数据进行锁定,防止其他程序进行更改,以确保更新的绝对成功

    OPTIMISTIC是相对比较好的一个选择,OPTIMISTIC不锁定任何数据,当需要在游标中更新数据时,如果底层表数据更新,则游标内数据更新不成功,如果,底层表数据未更新,则游标内表数据可以更新

2.打开游标

    当定义完游标后,游标需要打开后使用,只有简单一行代码:

OPEN test_Cursor
    注意,当全局游标和局部游标变量重名时,默认会打开局部变量游标

3.使用游标
   游标的使用分为两部分,一部分是操作游标在数据集内的指向,另一部分是将游标所指向的行的部分或全部内容进行操作
   只有支持6种移动选项,分别为到第一行(FIRST),最后一行(LAST),下一行(NEXT),上一行(PRIOR),直接跳到某行(ABSOLUTE(n)),相对于目前跳几行(RELATIVE(n)),例如:

     8

    对于未指定SCROLL选项的游标来说,只支持NEXT取值.
    第一步操作完成后,就通过INTO关键字将这行的值传入局部变量:

    比如下面代码:

    10

    9

      游标经常会和全局变量@@FETCH_STATUS与WHILE循环来共同使用,以达到遍历游标所在数据集的目的,例如:

    11

4.关闭游标

    在游标使用完之后,一定要记得关闭,只需要一行代码:CLOSE+游标名称

CLOSE test_Cursor
 
5.释放游标

    当游标不再需要被使用后,释放游标,只需要一行代码:DEALLOCATE+游标名称

DEALLOCATE test_Cursor
 
对于游标一些优化建议

     如果能不用游标,尽量不要使用游标
     用完用完之后一定要关闭和释放
     尽量不要在大量数据上定义游标
     尽量不要使用游标上更新数据
     尽量不要使用insensitive, static和keyset这些参数定义游标
     如果可以,尽量使用FAST_FORWARD关键字定义游标
     如果只对数据进行读取,当读取时只用到FETCH NEXT选项,则最好使用FORWARD_ONLY参数
 
总结

     本文从游标的基本概念,到生命周期来谈游标。游标是非常邪恶的一种存在,使用游标经常会比使用面向集合的方法慢2-3倍,当游标定义在大数据量时,这个比例还会增加。如果可能,尽量使用while,子查询,临时表,函数,表变量等来替代游标,记住,游标永远只是你最后无奈之下的选择,而不是首选。
========

T-SQL游标使用

http://blog.csdn.net/ht_927/article/details/6006778  

使用游标(cursor) 的一个主要的原因就是把集合操作转换成单个记录处理方式。用 SQL 语言从数据库中检索数据后,结果放在内存的一块区域中, 且结果往往是一个含有多个记录的集合。游标机制允许用户在 SQL server 内逐行地访问这些记录,按照用户自己的意愿来显示和处理这些记录。
1. 为何使用游标:
         使用游标 (cursor) 的一个主要的原因就是把集合操作转换成单个记录处理方式。用 SQL 语言从数据库中检索数据后,结果放在内存的一块区域中,且结果往往是一个含有多个记录的集合。游标机制允许用户在 SQL server 内逐行地访问这些记录,按照用户自己的意愿来显示和处理这些记录。
2. 如何使用游标:
     一般地,使用游标都遵循下列的常规步骤:
      (1)  声明游标。把游标与 T-SQL 语句的结果集联系起来。 
      (2)  打开游标。 
      (3)  使用游标操作数据。 
      (4)  关闭游标。
2.1. 声明游标
DECLARE CURSOR 语句 SQL-92 标准语法格式:
DECLARE 游标名 [ INSENSITIVE ] [ SCROLL ] CURSOR
FOR   sql-statement
Eg:
Declare MycrsrVar Cursor
FOR Select * FROM tbMyData
2.2  打开游标
OPEN MycrsrVar
当游标被打开时,行指针将指向该游标集第 1 行之前,如果要读取游标集中的第 1 行数据,必须移动行指针使其指向第 1 行。就本例而言,可以使用下列操作读取第 1 行数据:
    FETCH FIRST from E1cursor
     或 FETCH NEXT from E1cursor
2.3      使用游标操作数据    
下面的示例用 @@FETCH_STATUS 控制在一个 WHILE 循环中的游标活动
/* 使用游标读取数据的操作如下。 */
DECLARE E1cursor cursor     /* 声明游标,默认为 FORWARD_ONLY 游标 */
FOR SELECT * FROM c_example
OPEN E1cursor               /* 打开游标 */
FETCH NEXT from E1cursor    /* 读取第 1 行数据 */
WHILE @@FETCH_STATUS = 0    /* 用 WHILE 循环控制游标活动 */
BEGIN
         FETCH NEXT from E1cursor  /* 在循环体内将读取其余行数据 */
END
CLOSE E1cursor              /* 关闭游标 */
DEALLOCATE E1cursor         /* 删除游标 */

2.4    关闭游标
    使用CLOSE 语句关闭游标
CLOSE { { [ GLOBAL ]游标名  } | 游标变量名  }
使用DEALLOCATE 语句删除游标,其语法格式如下:
DEALLOCATE { { [ GLOBAL ]游标名  } | @ 游标变量名 
3. FETCH操作的简明语法如下:
 FETCH
         [ NEXT | PRIOR | FIRST | LAST]
FROM
{游标名  | @ 游标变量名  } [ INTO @ 变量名  [ , …] ]
参数说明:
NEXT  取下一行的数据,并把下一行作为当前行 ( 递增 ) 。由于打开游标后,行指针是指向该游标第 1 行之前,所以第一次执行 FETCH NEXT 操作将取得游标集中的第 1 行数据。 NEXT 为默认的游标提取选项。
INTO @变量名 [,…]  把提取操作的列数据放到局部变量中。列表中的各个变量从左到右与游标结果集中的相应列相关联。各变量的数据类型必须与相应的结果列的数据类型匹配或是结果列数据类型所支持的隐性转换。变量的数目必须与游标选择列表中的列的数目一致。
--------------------------------------------------------------------------------------------------------------------------------
每执行一个FETCH 操作之后,通常都要查看一下全局变量 @@FETCH_STATUS 中的状态值,以此判断 FETCH 操作是否成功。该变量有三种状态值:
· 0 表示成功执行 FETCH 语句。
· -1 表示 FETCH 语句失败,例如移动行指针使其超出了结果集。
· -2 表示被提取的行不存在。
由于@@FETCH_STATU 是全局变量,在一个连接上的所有游标都可能影响该变量的值。因此,在执行一条 FETCH 语句后,必须在对另一游标执行另一 FETCH 语句之前测试该变量的值才能作出正确的判断。 

--示例 
declare @Familyid int 
declare @address nvarchar(100)
DECLARE E1cursor cursor       /* 声明游标,默认为 FORWARD_ONLY 游标  */ 
FOR SELECT address FROM FamilyInfo where Family_id<10 
OPEN E1cursor                 /* 打开游标  */ 
FETCH NEXT from E1cursor into @address    /* 读取第 1 行数据 */ 
WHILE @@FETCH_STATUS = 0      /* 用 WHILE 循环控制游标活动  */ 
BEGIN 
  SELECT * FROM mHUB_fnSplit(@address,'%') where @@rowcount<4 
    FETCH NEXT from E1cursor into @address  /*读取其它记录 */ 
END
CLOSE E1cursor               
 DEALLOCATE E1cursor  

========

SQL Server游标

http://www.cnblogs.com/knowledgesea/p/3699851.html
什么是游标
结果集,结果集就是select查询之后返回的所有行数据的集合。

游标则是处理结果集的一种机制吧,它可以定位到结果集中的某一行,多数据进行读写,也可以移动游标定位到你所需要的行中进行操作数据。

一般复杂的存储过程,都会有游标的出现,他的用处主要有:

定位到结果集中的某一行。
对当前位置的数据进行读写。
可以对结果集中的数据单独操作,而不是整行执行相同的操作。
是面向集合的数据库管理系统和面向行的程序设计之间的桥梁。
游标的分类
根据游标检测结果集变化的能力和消耗资源的情况不同,SQL Server支持的API服务器游标分为一下4种:

静态游标: 静态游标的结果集,在游标打开的时候建立在TempDB中,不论你在操作游标的时候,如何操作数据库,游标中的数据集都不会变。例如你在游标打开的时候,对游标查询的数据表数据进行增删改,操作之后,静态游标中select的数据依旧显示的为没有操作之前的数据。如果想与操作之后的数据一致,则重新关闭打开游标即可。
动态游标:这个则与静态游标相对,滚动游标时,动态游标反应结果集中的所有更改。结果集中的行数据值、顺序和成员在每次提取时都会变化。所有用户做的增删改语句通过游标均可见。如果使用API函数或T-SQL Where Current of子句通过游标进行更新,他们将立即可见。在游标外部所做的更新直到提交时才可见。
只进游标:只进游标不支持滚动,只支持从头到尾顺序提取数据,数据库执行增删改,在提取时是可见的,但由于该游标只能进不能向后滚动,所以在行提取后对行做增删改是不可见的。
键集驱动游标:打开键集驱动游标时,该有表中的各个成员身份和顺序是固定的。打开游标时,结果集这些行数据被一组唯一标识符标识,被标识的列做删改时,用户滚动游标是可见的,如果没被标识的列增该,则不可见,比如insert一条数据,是不可见的,若可见,须关闭重新打开游标。
静态游标在滚动时检测不到表数据变化,但消耗的资源相对很少。动态游标在滚动时能检测到所有表数据变化,但消耗的资源却较多。键集驱动游标则处于他们中间,所以根据需求建立适合自己的游标,避免资源浪费。。

游标的生命周期
游标的生命周期包含有五个阶段:声明游标、打开游标、读取游标数据、关闭游标、释放游标。

 1.声明游标,语法

复制代码
DECLARE cursor_name CURSOR [ LOCAL | GLOBAL ] 
     [ FORWARD_ONLY | SCROLL ] 
     [ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ] 
     [ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ] 
     [ TYPE_WARNING ] 
     FOR select_statement 
     [ FOR UPDATE [ OF column_name [ ,...n ] ] ]

复制代码
参数说明:

cursor_name:游标名称。
Local:作用域为局部,只在定义它的批处理,存储过程或触发器中有效。
Global:作用域为全局,由连接执行的任何存储过程或批处理中,都可以引用该游标。
[Local | Global]:默认为local。
Forward_Only:指定游标智能从第一行滚到最后一行。Fetch Next是唯一支持的提取选项。如果在指定Forward_Only是不指定Static、KeySet、Dynamic关键字,默认为Dynamic游标。如果Forward_Only和Scroll没有指定,Static、KeySet、Dynamic游标默认为Scroll,Fast_Forward默认为Forward_Only
Static:静态游标
KeySet:键集游标
Dynamic:动态游标,不支持Absolute提取选项
Fast_Forward:指定启用了性能优化的Forward_Only、Read_Only游标。如果指定啦Scroll或For_Update,就不能指定他啦。
Read_Only:不能通过游标对数据进行删改。
Scroll_Locks:将行读入游标是,锁定这些行,确保删除或更新一定会成功。如果指定啦Fast_Forward或Static,就不能指定他啦。
Optimistic:指定如果行自读入游标以来已得到更新,则通过游标进行的定位更新或定位删除不成功。当将行读入游标时,sqlserver不锁定行,它改用timestamp列值的比较结果来确定行读入游标后是否发生了修改,如果表不行timestamp列,它改用校验和值进行确定。如果已修改改行,则尝试进行的定位更新或删除将失败。如果指定啦Fast_Forward,则不能指定他。
Type_Warning:指定将游标从所请求的类型隐式转换为另一种类型时向客户端发送警告信息。
For Update[of column_name ,....] :定义游标中可更新的列。
2.声明一个动态游标

declare orderNum_02_cursor cursor scroll
for select OrderId from bigorder where orderNum='ZEORD003402'
3.打开游标

--打开游标语法
open [ Global ] cursor_name | cursor_variable_name
cursor_name:游标名,cursor_variable_name:游标变量名称,该变量引用了一个游标。

--打开游标
open orderNum_02_cursor
4.提取数据

复制代码
--提取游标语法
Fetch
[ [Next|prior|Frist|Last|Absoute n|Relative n ]
from ]
[Global] cursor_name
[into @variable_name[,....]]
复制代码
参数说明:

Frist:结果集的第一行
Prior:当前位置的上一行
Next:当前位置的下一行
Last:最后一行
Absoute n:从游标的第一行开始数,第n行。
Relative n:从当前位置数,第n行。
Into @variable_name[,...] : 将提取到的数据存放到变量variable_name中。
例子:

复制代码
--提取数据
fetch first from orderNum_02_cursor
fetch relative 3 from orderNum_02_cursor
fetch next from orderNum_02_cursor
fetch absolute 4 from orderNum_02_cursor
fetch next from orderNum_02_cursor
fetch last from orderNum_02_cursor 
fetch prior from orderNum_02_cursor
select * from bigorder where orderNum='ZEORD003402'
复制代码
结果(对比一下,就明白啦):

例子:

--提取数据赋值给变量
declare @OrderId int
fetch absolute 3 from orderNum_02_cursor into @OrderId
select @OrderId as id
select * from bigorder where orderNum='ZEORD003402'
结果:

通过检测全局变量@@Fetch_Status的值,获得提取状态信息,该状态用于判断Fetch语句返回数据的有效性。当执行一条Fetch语句之后,@@Fetch_Status可能出现3种值:0,Fetch语句成功。-1:Fetch语句失败或行不在结果集中。-2:提取的行不存在。

这个状态值可以帮你判断提取数据的成功与否。

复制代码
declare @OrderId int
fetch absolute 3 from orderNum_02_cursor into @OrderId
while @@fetch_status=0  --提取成功,进行下一条数据的提取操作
 begin
   select @OrderId as id
   fetch  next from orderNum_02_cursor into @OrderId  --移动游标
 end 
复制代码
5.利用游标更新删除数据 

--游标修改当前数据语法
Update 基表名 Set 列名=值[,...] Where Current of 游标名
--游标删除当前数据语法
Delete 基表名  Where Current of 游标名
复制代码
---游标更新删除当前数据
---1.声明游标
declare orderNum_03_cursor cursor scroll
for select OrderId ,userId from bigorder where orderNum='ZEORD003402'
--2.打开游标
open orderNum_03_cursor
--3.声明游标提取数据所要存放的变量
declare @OrderId int ,@userId varchar(15)
--4.定位游标到哪一行
fetch First from orderNum_03_cursor into @OrderId,@userId  --into的变量数量必须与游标查询结果集的列数相同
while @@fetch_status=0  --提取成功,进行下一条数据的提取操作 
 begin
   if @OrderId=122182
     begin
     Update bigorder Set UserId='123' Where Current of  orderNum_03_cursor  --修改当前行
     end
   if @OrderId=154074
      begin
      Delete bigorder Where Current of  orderNum_03_cursor  --删除当前行
      end
   fetch next from orderNum_03_cursor into @OrderId ,@userId  --移动游标
 end  


6.关闭游标

 游标打开后,服务器会专门为游标分配一定的内存空间存放游标操作的数据结果集,同时使用游标也会对某些数据进行封锁。所以游标一旦用过,应及时关闭,避免服务器资源浪费。

--关闭游标语法
close [ Global ] cursor_name | cursor_variable_name
--关闭游标
close orderNum_03_cursor
7.删除游标

删除游标,释放资源

--释放游标语法
deallocate  [ Global ] cursor_name | cursor_variable_name
--释放游标
deallocate orderNum_03_cursor
========

T-SQL 游标 游标更新数据

http://blog.sina.com.cn/s/blog_56294d0a0101fj77.html
 游标的引入
 1 .在数据的开发过程中,从某一结果集中逐一读取一条记录,用游标解决,游标占资源大,确定不用后将其释放。
 2 .声明游标(四个组成部分)
 ( 1 ).declare游标
 ( 2 ).open游标
 ( 3 ).从一个游标中fetch信息
 ( 4 ).close或deallocate游标
 一、声明游标主要内容:
 ( 1 ).游标名字
 ( 2 ).数据来源表和列
 ( 3 ).选取条件
 ( 4 ).属性仅读或可修改
 1 .语法格式:
 declare  游标名称  [ scroll ]   cursor 
 [ local|global ] 
 [ forward_only|scroll ] 
 for  选择语句
 [ for[read_only|update [of 字段名称1,字段名称2, ] ]]
 其中:
 1 > .local | global指定该游标的作用域是局部的还是全局的。
 2 > .如果把forward_only选择为forward_only, 则游标只能从第一行滚动到最后一行。
 3 > .scroll表明所有的提取操作,如first,last,prior, next ,relative,absolute都可用。如不使用该保留字,那么只能进行next提取操作。
 4 > .选择语句:是定义结果集的select语句,应该注意的是在游标中不能使用compute, compute   by   for  browse  into语句.
 5 > . read   only :表明不允许游标内的数据被更新。
 6 > . update [ of 字段名1[, n ] ]:定义在游标中可被修改的列。
 
 例1:标准游标
 declare  taihang  cursor 
 for 
 select  id,name,address,city,state
 from   table 

 例2:只读游标
 declare  taihang  cursor 
 for 
 select  id,name,address,city,atate
 from   table 
 for   read   only 

 例3:更新游标
 declare  taihang  cursor 
 for 
 select  name,address
 from   table 
 for   update 

 
 二、打开游标
 1 .声明之后,如要从游标中读取数据,必须打开游标,使用open命令。
 语法:
 open  游标名称
 注意:
 1 > .在打开游标时,如果游标声明语句中使用了insensitive保留字,则open产生一个临时表来存放结果集。如果在结果集中任何一行数据的大小超过SQL Server定义的最大行尺寸时,open命令将失败。
 2 > .insensitive: 表明SQL Server会将游标定义所选取出来的数据记录存放在一临时表内,(建立在tempdb数据库下)对该游标的操作皆由临时表来应答。因此,对 基本表的修改并不影响游标提取数据,即游标不会随着基本表内容的改变面改变,同时也不法通过游标来更新基本表。
 
 如果不使用该保留字,那么对基本表的更新,删除都会公映到游标中。
 
 三、读取游标中的数据- fetch 
 1 .当游标被成功打开以后就可以从游标中逐行地读取数据以时行相关处理。从游标中读取数据主要使用fetch命令。
 语法:
 fetch 
 [ [next|prior|first|last
 |absolute{n|@nvar}
 |relative{n|@nvar} ] 
 from ] cursor_name
 [ into @variable_name1,@variable_name2 ] 
 注:
 1 > . next :返回结果集中当前行的下一行,并增加当前行数为返回行行数。如果fetch next是第一次读取游标中数据,则返回结果集中的第一行而不是第二行。
 2 > .prior:返回结果集中当前行的前一行,并减少当前行数为返回行行数。如果fetch prior是第一次读取游标中的数据,刚无数据记录返回,并把游标位置设为第一行。
 3 > .first:返回游标中的第一行。
 4 > .last:返回游标中的最后一行。
 5 > .absolute{n | @nvar }:如果N或 @nvar为正数 ,则表示从游标中返回的数据行数。如果N或 @nvar为负数,则返回游标内从最后一行数据算起的第N或 @nvar行数据 。若N或 @nvar超过游标的数据子集范畴 ,则@@fetch_status返回 - 1 。在该情况下,如果N或 @nvar为负数 ,则再执行fetch next命令会得到第一行数据;如果N或 @nvar为正值 ,如执行fetch prior命令刚会得到最后一行数据。N或 @nvar可以是固定值 ,也可以是smallint,tinyint或int类型的变量。
 6 > .relative{N | @nvar }:若N或 @nvar为正数 ,则读取游标当前位置起向后的第N或 @nvar行数据 。如果N或@nvar为负数 ,则返回游标当前位置起向前的第N或 @nvar行数据 。若N或 @nvar超过游标的数据子集范畴 ,则 @@fetch_status返回 - 1 。在该情况下,如果N或 @nvar为负数 ,则再执行fetch next命令会得到第一行数据;如果N或 @nvar为正值 ,如执行fetch prior命令刚会得到最后一行数据。N或 @nvar可以是固定值 ,也可以是smallint,tinyint或int类型的变量。
 7 > . into @variable_name [ , n ] :允许使用fetch命令读取的数据存放在多个变量中;在变量行中的每个变量必须与游标结果集中相应的列相对应,每一变量的数据类型也要与游标中的数据列的数据类型相匹配。
 
 2 .检查游标状态
 @@fetch_status :全局变量,返回上次执行fetch命令的状态,在每次用fetch从游标中读取数据时,都应检查该变量以确定上次fetch操作是否成功,来决定如何进行下一步处理。 @@fetch_status变量有三个不同返回值。
 1 > . 0 :表示成功取出了一行。
 2 > . - 1表示未取到数据。游标位置超出结果集。
 3 > . - 2表示返回的行已经不再是结果集的一个成员,这种情况只有在游标不是insensitive的情况下出现,即其它进程已删除了行或改变了游标打开的关键值。
 
 3 .编辑当前游标行
 通 常,用游标来从基础表中检索数据,以实现对数据行处理,在修改游标中的数据,即进行定位更新或删除游标所包含的数据,所以必须执行另外的更新或删除命令, 并在where子句中重新给定条件才能修改到该行数据,但是如果在声明游标时使用了for update语句那么就可以在update或delete命令 中以where  current  of关键字直接修改或删除当前游标中所存储的数据,而不必使用where子句重新给出指定条件。当改变游标中数据时,这种变化会自动地影响到游标的基础表。但是如果在声明游标时选择了insensitive选项时,该游标中的数据不能被修改。
 
 进行定位修改或删除游标中的数据的语法规则语法:
 update  table_name
 set  column_name1 = {expression1 | null (select_statement)}
   [ ,column_name2={expression2|null(select_statement)} ] 
 where   current   of  cursor_name
 
 delete   from  table_name
 where   current   of  cursor_name
 其中:
 1 > .table_name:是update或delete的表名。
 2 > .column_name:uqdate的列名
 3 > .cursor_name:游标名
 
 例1:首先声明一个游标
 
declare  authors_cur scroll  cursor 
 for 
 select   *   from  authors
 for   update   of  au_lname,au_fname
 
 更新authors表中的au_lname和au_fname列
 
update  authors
 set  au_lname = ' china ' ,au_fname = ' asia ' 
 where   current   of  authors_cur
 
 删除authors表中的一行数据
 delete   from  authors
 where   current   of  authors_cur
 注:以上的更新或删除操作总是在游标的当前位置,
 
 例:下面是一个完整的定位更新的例子。
 
declare   @au_id   int ( 11 ), @au_lname   varchar ( 40 ), @au_fname   varchar ( 20 )
 declare  authors_cur  cursor 
 for 
 select  au_id,au_lname,au_fname  from  authors
 for   update   of  au_id,aulname,au_fname
 open  authors_cur   
 fetch   next   from  authors_cer  into   @au_id , @au_lname , @au_fname 
 while   @@fetch_status = 0    
 begin  
   if   @au_id = ' 172-32-1176 ' 
   update  authors
 set  au_lname = ' smith ' ,au_fname = ' jake ' 
 where   current   of  authors_cur
  
 fetch   next   from  authors_cer  into   @au_id , @au_lname , @au_fname 
 end 
 deallocate  authors_cur   

  四、释放游标
 1 .关闭游标
 使用close命令关闭游标,在处理完游标中数据之后,发布关闭游标来释放数据结果集和定位于数据记录上的锁,close语句关闭游标但不释放游标占用的数据结构。如果准备在随后的使用中再次打开游标,则应使用open命令。
 语法: close  游标名称
 2 .释放游标
 在使用游标时各种针对游标的操作或者引用游标各或者引用指向游标的游标变量,当close命令关闭游标时并没有释放游标占用的数据结构。因此常使用deallocate命令删除掉游标与游标名或游标变量之间的联系,并且释放游标占用的所有系统资源。
 语法: deallocate  游标名称
========

请问怎么用T-sql实现游标的递归


好象TSQL里面游标是个全局变量
有没有其他方法可以解决啊

可以借助存储过程的递归,在存储过程内部使用LOCAL声明游标为局部游标。

create     FUNCTION   dbo.GetSubClass(@Code_No   varchar(50),@IdStr   varchar(8000)='',@LevelCount   int=-1)     
  /*   
  参数: @Code_No   ,被搜索子类的ID   
  @IdStr,一个特殊参数,用于在递归中传数据,注意:调用函数时一定要传入‘’空值   
  @LevelCount   用于判断是不是递归调用的最上层   
  */   
  RETURNS   Varchar(8000)   
    AS       
  BEGIN     
    
  Declare   @single_no   varchar(50),   @TC_ID   varchar(50),@TC_PID   Varchar(50),@StartLevel   int,@Id32   int,@Ma_price   Numeric(19,3)   
    
  if   @LevelCount=-1   
  begin   
  set   @StartLevel=@@NESTLEVEL   
  set   @LevelCount=@StartLevel   
  end   
  else     
  set   @StartLevel=-1   
      
    
  If   @IdStr=''   Set   
      
          @IdStr=''''+@InputId   +''''   
      
  DECLARE   TreeClass   CURSOR   local   FOR   --定义游标   
      Select   b.single_no,b.Code_No   From   Mrp_Modec   a   ,Mrp_Mode   b   where   a.single_no=b.single_no   and   In_Code=   @InputId   
          
  OPEN   TreeClass   
  FETCH   NEXT   FROM   TreeClass   
  INTO   @single_no,@TC_ID   
    
  WHILE   @@FETCH_STATUS   =   0 --循环游标,即循环当前类的弟一级子类   
  BEGIN   
                if         exists(select   *   from   mrp_modec     )     
                          
                                  select   @Ma_price=Sum(sta_qty*u_price)   from       Mrp_Modec   Where       single_no=@single_no       
                    update   表名   SET   字段=   @Ma_price   WHERE       single_no=@single_no     --这里为什么通不过   
      select   @IdStr=   @IdStr+','+cast(@tC_ID   as   varchar)+''''   
    
  if   @@NESTLEVEL<32   
        
                                  set   @IdStr=   dbo.GetSubClass(@TC_ID,@IdStr,@LevelCount)   --递归。   
      
  else   
  set   @IdStr='['+cast(@tC_ID   as   varchar)+']'+@IdStr   
    
    
  FETCH   NEXT   FROM   TreeClass   iNTO   @single_no,@tC_ID     
    
  End   
    
  CLOSE   TreeClass   
  DEALLOCATE   TreeClass   
    
  /*while   @StartLevel=@@NESTLEVEL   and   charindex(']',@IdStr)>0   
  begin   
  set   @Id32=substring(@IdStr,2,charindex(']',@IdStr)-2)   
  set   @IdStr=dbo.FN_32GetSubClass   (@Id32,@IdStr,@LevelCount)   
  set   @IdStr=replace(@IdStr,'['+cast(@Id32   as   varchar)+']','')   
  end   
  */   
  Return     @IdStr   
    
  END   
  
但是我还要输出游标啊 
得到一个结果集
对这个结果集在操作
其中要用到递归

楼主参考一下:
http://community.csdn.net/Expert/topic/4896/4896332.xml?temp=.569317

游标默认定义是global

用下面的定义就可以了

declare 游标名 CURSOR LOCAL  -- LOCAL指定游标为局部的(默认是GLOBAL, 全局的)
FOR

但是递归怎么办啊 
输出参数为游标
========

猜你喜欢

转载自blog.csdn.net/bcbobo21cn/article/details/77159949