了解游标
游标提供了一种对从表中检索出的数据进行操作的灵活手段,就本质而言,游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。游标总是 与一条T_SQL 选择语句相关联因为游标由结果集(可以是零条、一条或由相关的选择语句检索出的多条记录)和结果集中指向特定记录的游标位置组成。当决定对结果集进行处理 时,必须声明一个指向该结果集的游标。
游标通过以下方式来扩展结果处理:
允许定位在结果集的特定行。
从结果集的当前位置检索一行或一部分行。
支持对结果集中当前位置的行进行数据修改。
为由其他用户对显示在结果集中的数据库数据所做的更改提供不同级别的可见性支持。
提供脚本、存储过程和触发器中用于访问结果集中的数据的 Transact-SQL 语句。
游标进程
1、将游标与 Transact-SQL 语句的结果集相关联,并且定义该游标的特性,例如是否能够更新游标中的行。(创建游标)
2、执行 Transact-SQL 语句以填充游标。(打开游标)
3、从游标中检索您想要查看的行。从游标中检索一行或一部分行的操作称为提取。执行一系列提取操作以便向前或向后检索行的操作称为滚动。(提取数据)
4、根据需要,对游标中当前位置的行执行修改操作(更新或删除)。(处理事务)
5、关闭释放游标。(释放游标)
游标类型:
SQL Server 支持的四种 API 服务器游标类型是:
静态游标:静态游标是在打开游标时在tempdb中建立SELECT结果集的快照。静态游标总是按照打开游标时的原样显示结果集, 不反应它所选举行的更新情况。
动态游标:动态游标与静态游标相对。当滚动游标时,动态游标反映结果集中所做的所有更改。结果集中的行数据值、顺序和成员在每次提取时都会改变。所有用户做的全部 UPDATE、INSERT 和 DELETE 语句均通过游标可见。
只进游标:只进游标不支持滚动,它只支持游标从头到尾顺序提取。
键集游标:该游标中各行的成员身份和顺序是固定的。由键集驱动的游标由一组唯一标识符(键)控制,这组键称为键集。键是根据以唯一方式标识结果集中各行的 一组列生成的。键集是打开游标时来自符合 SELECT 语句要求的所有行中的一组键值。由键集驱动的游标对应的键集是打开该游标时在 tempdb 中生成的。
游标行为:
可滚动 :如果在 DECLARE 语句指定了关键字 SCROLL,或 SQL_ATTR_CURSOR_SCROLLABLE 设置为 SQL_SCROLLABLE,则游标支持所有的提取选项。
敏感性: 游标的敏感性行为定义了对基行(用于建立游标)所做的更新是否对游标可见
游标名称的作用域:
Microsoft SQL Server 2005 支持在 DECLARE CURSOR 语句中使用 GLOBAL 和 LOCAL 关键字定义游标名称的作用域。GLOBAL 指定游标名称对连接是全局性的。LOCAL 指定游标名称对含有 DECLARE CURSOR 语句的存储过程、触发器或批处理是局部性的。
局部游标为存储过程和触发器中实现的游标提供重要的保护作用。全局游标可以在声明它们的存储过程或触发器的外部引用。因此,它们可能会被存储过程或触发器 外部的语句无意中更改。因为不能在存储过程外部引用局部游标,所以局部游标比全局游标更安全,除非故意将局部游标作为游标输出参数传递回调用方。
游标提取和滚动:
FETCH FIRST:提取游标中的第一行。
FETCH NEXT:提取上一个提取行后面的行。
FETCH PRIOR:提取上一个提取行前面的行。
FETCH LAST:提取游标中的最后一行。
FETCH ABSOLUTE n:如果 n 为正整数,则提取游标中从第 1 行开始的第 n 行。如果 n 为负整数,则提取游标中的倒数第 n 行。如果 n 为 0,则不提取行。
FETCH RELATIVE n:提取从上一个提取行数起的第 n 行。如果 n 为正数,则提取上一个提取行后面的第 n 行。如果 n 为负数,则提取上一个提取行前面的第 n 行。如果 n 为 0,则再次提取同一行。
以上语句除FETCH NEXT外只对可滚动游标有效。
通过TSQL 实现游标:
声明 Transact-SQL 变量包含游标返回的数据。
使用 DECLARE CURSOR 语句将 Transact-SQL 游标与 SELECT 语句相关联。
使用 OPEN 语句执行 SELECT 语句并填充游标。
使用 FETCH INTO 语句提取单个行,并将每列中的数据移至指定的变量中。
使用 CLOSE 语句结束游标的使用。使用DEALLOCATE 语句则完全释放分配给游标的资源。
DECLARE cursor_name CURSOR
[ LOCAL | GLOBAL ] --作用域:局部的[默认]/全局的。
[ FORWARD_ONLY | SCROLL ] --只进[默认]/滚动
[ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ] --游标类型STATIC[默认]
[ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ] --设定锁的形式。禁止通过该游标进行更新、指定通过游标进行的定位更新或删除保证会成功、指定如果行自从被读入游标以来已得到更新,则通过游标进行的定位更新或定位删除不会成功
[ TYPE_WARNING ] --指定如果游标从所请求的类型隐式转换为另一种类型,则向客户端发送警告消息。
FOR select_statement --定义游标结果集的标准 SELECT 语不允许使用关键字 COMPUTE、COMPUTE BY、FOR BROWSE 和 INTO。
[ FOR UPDATE [ OF column_name [ ,...n ] ] ][;] --定义游标中可更新的列。如果提供了 OF column_name [,...n],则只允许修改列出的列。如果指定了 UPDATE,但未指定列的列表,则除非指定了 READ_ONLY 并发选项,否则可以更新所有的列。
示例:
SET NOCOUNT ON
DECLARE @vendor_id int, @vendor_name nvarchar(50), @message varchar(80), @product nvarchar(50) --声明CURSOR中使用的变量
PRINT '-------- Vendor Products Report --------'
--定义游标
DECLARE vendor_cursor CURSOR FOR
SELECT VendorID, Name
FROM Purchasing.Vendor
WHERE PreferredVendorStatus = 1
ORDER BY VendorID
--打开游标
OPEN vendor_cursor
--取数据
FETCH NEXT FROM vendor_cursor
INTO @vendor_id, @vendor_name
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT ' '
SELECT @message = '----- Products From Vendor: ' +
@vendor_name
PRINT @message
-- Declare an inner cursor based
-- on vendor_id from the outer cursor.
DECLARE product_cursor CURSOR FOR
SELECT v.Name
FROM Purchasing.ProductVendor pv, Production.Product v
WHERE pv.ProductID = v.ProductID AND
pv.VendorID = @vendor_id-- Variable value from the outer cursor
OPEN product_cursor
FETCH NEXT FROM product_cursor INTO @product
IF @@FETCH_STATUS <> 0
PRINT ' <<None>>'
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @message = ' ' + @product
PRINT @message
FETCH NEXT FROM product_cursor INTO @product
END
CLOSE product_cursor
DEALLOCATE product_cursor
-- Get the next vendor.
FETCH NEXT FROM vendor_cursor
INTO @vendor_id, @vendor_name
END
CLOSE vendor_cursor
DEALLOCATE vendor_cursor
选择游标类型的规则:
尽可能使用默认结果集。如果需要滚动操作,将小结果集缓存在客户端,并在缓存中滚动而不是要求服务器实现游标,其效率可能更高。
将整个结果集提取到客户端(如产生报表)时,使用默认设置。默认结果集是将数据传送到客户端的最快方式。
如果应用程序正在使用定位更新,则不能使用默认结果集。
默认结果集必须用于将生成多个结果集的 Transact-SQL 语句或 Transact-SQL 语句批。
动态游标的打开速度比静态游标或由键集驱动的游标的打开速度快。当打开静态游标和由键集驱动的游标时,必须生成内部临时工作表,而动态游标则不需要。
在联接中,由键集驱动的游标和静态游标的速度可能比动态游标的速度快。
如果要进行绝对提取,必须使用由键集驱动的游标或静态游标。
静态游标和由键集驱动的游标增加了 tempdb 的使用率。静态服务器游标在 tempdb 中创建整个游标,由键集驱动的游标则在 tempdb 中创建键集。
如果游标在整个回滚操作期间必须保持打开状态,请使用同步静态游标,并将 CURSOR_CLOSE_ON_COMMIT 设为 OFF。
服务器游标元数据:
有几个系统函数可以报告服务器游标或分配给游标变量的服务器游标的状态信息:
CURSOR_STATUS:指明游标是打开还是关闭,或者游标变量当前是否与游标相关联。
@@FETCH_STATUS 指明为连接执行的最后一次提取操作是成功还是失败。
@@CURSOR_ROWS 报告为连接打开的最后一个游标中填充的行数。
有几个系统存储过程可以报告服务器游标或分配给游标变量的服务器游标的特征:
sp_describe_cursor :返回描述游标属性(例如游标的作用域、名称、类型、状态和行数)的游标。
sp_describe_cursor_columns:返回描述游标中每一列的属性(例如列的名称、位置、大小和数据类型)的游标。