SQL Server的游标之我见

T-SQL语句对表的操作通常是一个结果集。游标是SQL Server提供的一种机制,它能够对一个结果集进行逐行处理。

游标的优点:

1.允许程序对由查询语句select返回的行集合中的每一行执行相同或不同的操作,而不是对整个行集合执行同一个操作;

2.提供基于游标位置的表中的行进行删除和更新的能力;

3.游标实际上作为面向集合的数据库管理系统和面向行的程序设计之间的桥梁,使这两种处理方法通过游标沟通起来。

游标的使用顺序:声明游标,打开游标,读取游标,关闭游标,删除游标。

DECLARE <游标名> [INSENSITIVE][SCROLL] CURSORFOR 这里我说一下游标中级应用中的[INSENSITIVE][SCROLL]

INSENSITIVE

  表明MS SQL SERVER 会将游标定义所选取出来的数据记录存放在一临时表内(建立在tempdb 数据库下)。对该游标的读取操作皆由临时表来应答。因此,对基本表的修改并不影响游标提取的数据,即游标不会随着基本表内容的改变而改变,同时也无法通过游标来更新基本表。如果不使用该保留字,那么对基本表的更新、删除都会反映到游标中。

  另外应该指出,当遇到以下情况发生时,游标将自动设定INSENSITIVE 选项。

a.SELECT 语句中使用DISTINCT GROUP BY HAVING UNION 语句;

b.使用OUTER JOIN;

c.所选取的任意表没有索引;

d.将实数值当作选取的列。

SCROLL

表明所有的提取操作(FIRST LAST PRIOR NEXT RELATIVE ABSOLUTE)都可用。如果不使用该保留字,那么只能进行NEXT 提取操作。由此可见,SCROLL 极大地增加了提取数据的灵活性,可以随意读取结果集中的任一行数据记录,而不必关闭再重开游标。

在从游标中取值的过程中,可以在结果集中的每一行上来回移动和处理。如果游标定义成了可滚动的(在声明时使用SCROLL关键字),则任何时候都可取出结果集中的任意行。对于非滚动的游标,只能对当前行的下一行实施取操作。结果集可以取到局部变量中。Fetch命令的语法如下:

FETCH [NEXT | PRIOR| FIRST | LAST |ABSOLUTE {n | @nvar} | RELATIVE {n | @nvar}]
FROM [GLOBAL] cursor_name} | cursor_variable_name}
[INTO @variable_name ][,……n]]
NEXT指明从当前行的下一行取值。

PRIOR指明从当前行的前一行取值,与next相反,取得是上一行的值。

FIRST是结果集的第一行。

LAST是结果集的最后一行。

ABSOLUTE n表示结果集中的第n行,该行数同样可以通过一个局部变量传播。行号从0开始,所以n0时不能得到任何行。

RELATIVE n表示要取出的行在当前行的前n行或后n行的位置上。如果该值为正数,则要取出的行在当前行前n行的位置上,如果该值为负数,则返回当前行的后n行。

INTO @cursor_variable_name表示游标列值存储的地方的变量列表。该列表中的变量数应该与DECLARE语句中选择语句所使用的变量数相同。变量的数据类型也应该与被选择列的数据类型相同。直到下一次使用FETCH语句之前,变量中的值都会一直保持。

每一次FETCH的执行都存储在系统变量@@fetch_status中。如果FETCH成功,则@@fetch_status被设置成0@@fetch_status-1表示已经到达了结果集的一部分(例如,在游标被打开之后,基表中的行被删除)。@@fetch_status可以用来构造游标处理的循环。

@@fetch_status是MSSQL的一个全局变量

其值有以下三种,分别表示三种不同含义:【返回类型integer】

0 FETCH 语句成功

-1 FETCH 语句失败或此行不在结果集中

-2 被提取的行不存在

@@fetch_status值的改变是通过fetch next from实现的,如“FETCH NEXT FROM Cursor”

@@fetch_status来控制while循环中的游标活动。

如:
DECLARE Employee_Cursor CURSOR FOR

SELECT BusinessEntityID, JobTitle

FROM AdventureWorks2012.HumanResources.Employee;

OPEN Employee_Cursor;

FETCH NEXT FROM Employee_Cursor;

WHILE @@FETCH_STATUS = 0

BEGIN

FETCH NEXT FROM Employee_Cursor;

END;

CLOSE Employee_Cursor;

DEALLOCATE Employee_Cursor;

GO