嵌套游标 function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();} 今天有人询问游标是否可以嵌套使用的问题,因为用于标识游标是否已经达到数据集结尾的标志值@@FETCH_STATUS是一个全局变量,那么如果出现游标嵌套的话可能造成内侧的游标完成数据集遍历以后导致外侧游标的无法再循环读取下一行的数据。先来看看SQL Server 2000中联机帮助的内容: @@FETCH_STATUS 返回被 FETCH 语句执行的最后游标的状态,而不是任何当前被连接打开的游标的状态。 返回值描述 0 FETCH 语句成功。 -1 FETCH 语句失败或此行不在结果集中。 -2 被提取的行不存在。语法 @@FETCH_STATUS 返回类型 integer 注释由于 @@FETCH_STATUS 对于在一个连接上的所有游标是全局性的,要小心使用 @@FETCH_STATUS 。在执行一条 FETCH 语句后,必须在对另一游标执行另一 FETCH 语句前测试 @@FETCH_STATUS 。在任何提取操作出现在此连接上前,@@FETCH_STATUS 的值没有定义。例如,用户从一个游标执行一条 FETCH 语句,然后调用一个存储过程,此存储过程打开并处理另一个游标的结果。当控制从被调用的存储过程返回后,@@FETCH_STATUS 反映的是在存储过程中执行的最后的 FETCH 语句的结果,而不是在存储过程被调用之前的 FETCH 语句的结果。示例下面的示例用 @@FETCH_STATUS 控制在一个 WHILE 循环中的游标活动。DECLARE Employee_Cursor CURSOR FORSELECT LastName, FirstName FROM Northwind.dbo.EmployeesOPEN Employee_CursorFETCH NEXT FROM Employee_CursorWHILE @@FETCH_STATUS = 0BEGIN FETCH NEXT FROM Employee_CursorENDCLOSE Employee_CursorDEALLOCATE Employee_Cursor从最开始的那句话“返回被 FETCH 语句执行的最后游标的状态,而不是任何当前被连接打开的游标的状态。”可以看出,@@FETCH_STATUS这个全局变量的确不是和某个特定的游标绑定在一起的,而是一个类似于我们声明的静态变量一样,谁都可以去修改它的值,而且一旦它的值出现了修改,那么所有使用到这个变量的对象都会受到影响。的确游标嵌套很容易引起混乱,但是游标的嵌套是可能的,原理也是利用上面这句话,如果我们在执行完成了内侧的游标后,先通过FETCH语句执行外侧的游标,这样如果外侧还存在记录没有遍历完成的话,那么此时@@FETCH_STATUS又会被重新设置为0,外侧的游标也可以继续进行遍历操作了。所以说解决问题的关键还是看FETCH语句的摆放位置。例如如下代码: --外侧游标(mc_AffectedEmployee); DECLARE mc_AffectedEmployee CURSOR LOCAL FOR --声明一个局部游标; SELECT DISTINCT infectRows.C_EMPLPOST_EMPLID FROM ( SELECT C_EMPLPOST_EMPLID FROM INSERTED UNION SELECT C_EMPLPOST_EMPLID FROM DELETED) infectRows --打开游标; OPEN mc_AffectedEmployee; --这里需要先执行一次FETCH语句,以便查看是否需要进行循环遍历;(这里很像IDataReader.Read()方法) FETCH NEXT FROM mc_AffectedEmployee INTO @EmployeeID WHILE(@@FETCH_STATUS = 0) BEGIN --Some T-SQL Statements here --声明内部游标(mc_AllPostID) DECLARE mc_AllPostID CURSOR LOCAL FOR SELECT C_EMPLPOST_POSTID FROM T_PERSONNEL_EMPLPOSITION WHERE C_EMPLPOST_EMPLID = @EmployeeID AND C_EMPLPOST_STARTDATE <= getDate() AND ((C_EMPLPOST_ENDDATE >= getDate()) OR (C_EMPLPOST_ENDDATE IS NULL)) AND C_EMPLPOST_DEPTID = @CurrentOrgCode; OPEN mc_AllPostID --同样这里需要先执行一次FETCH语句; FETCH NEXT FROM mc_AllPostID INTO @NowPostID; WHILE (@@FETCH_STATUS = 0) BEGIN --Some T-SQL Statements here. -- 这里需要执行FETCH语句为下次循环设置@@FETCH_STATUS; FETCH NEXT FROM mc_AllPostID INTO @NowPostID; END UPDATE T_PERSONNEL_EMPLINFO SET C_EMPLINFO_SHOWPOSTNAME = @ShowPostName WHERE C_EMPLINFO_EMPLID = @EmployeeID; CLOSE mc_AllPostID; DEALLOCATE mc_AllPostID; --*************************************************************************** --这里判断是否已经完成了数据集的遍历,如果已经完成那么就将循环标志值(@Loop)设置为假(0); --由于内侧的游标已经完成遍历,所以这里@@FETCH_STATUS = -1,通过FETCH语句,如果此时外侧的游标还存在没有遍历的记录,那么这里@@FETCH_STATUS又会被重新赋值为0,以便下次循环操作。 FETCH NEXT FROM mc_AffectedEmployee INTO @EmployeeID END --关闭游标; CLOSE mc_AffectedEmployee; DEALLOCATE mc_AffectedEmployee;
http://blog.csdn.net/vividboy/archive/2008/04/16/2298304.aspx