快速了解Transact-SQL游标名称的作用域
Microsoft® SQL Server™ 2000 支持 DECLARE CURSOR 语句上的 GLOBAL 和 LOCAL 关键字以定义游标名称的作用域。GLOBAL 指定游标名称对连接是全局性的。LOCAL 指定游标名称对含有 DECLARE CURSOR 语句的存储过程、触发器或批处理是局部性的。
在 Microsoft® SQL Server™ 7.0 版之前的版本中,Transact-SQL 游标的名称对连接而言是全局的。可以执行一个创建游标的存储过程,然后调用另一个存储过程从此游标中提取行:
USE pubsGOCREATE PROCEDURE OpenCrsr ASDECLARE SampleCrsr CURSOR FORSELECT au_lnameFROM authorsWHERE au_lname LIKE 'S%'OPEN SampleCrsrGOCREATE PROCEDURE ReadCrsr ASFETCH NEXT FROM SampleCrsrWHILE (@@FETCH_STATUS <> -1)BEGIN FETCH NEXT FROM SampleCrsrENDGOEXEC OpenCrsr /* DECLARES and OPENS SampleCrsr. */GOEXEC ReadCrsr /* Fetches the rows from SampleCrsr. */GOCLOSE SampleCrsrGODEALLOCATE SampleCrsrGO |
局部游标为存储过程和触发器中执行的游标提供了重要的保护作用。全局游标可以在声明它们的存储过程或触发器的外部被引用。因此,存储过程或触发器的外部语句可能会在无意中更改它们。因为不能在存储过程以外引用局部游标,因此局部游标比全局游标更安全,除非故意将局部游标作为游标输出参数返回调用方。
因为可以在存储过程或触发器的外部引用全局游标,所以全局游标可能会在无意中影响其它语句。例如,在存储过程中创建了一个名为 xyz 的全局游标,在存储过程结束时此游标是打开的。当此存储过程完成后若要使用 xyz 来声明另一个全局游标,则会因为使用重复的名称错误而导致失败。
全局游标和局部游标有各自的名称空间,因此可以同时有相同名称的全局游标和局部游标。接受游标命名参数的Transact-SQL 语句也支持 GLOBAL 关键字来标识名称的作用域。如果没有指定 GLOBAL,且在游标名称参数中同时有指定了此名称的全局游标和局部游标,则引用此局部游标。
如果 LOCAL和 GLOBAL 都没有指定,则数据库选项default to local cursor 控制由 DECLARE CURSOR 语句使用的默认值。如果 default to local cursor 为 true,Transact-SQL 游标默认为是局部的。如果此选项为 false,Transact-SQL 游标默认为是全局游标。在 SQL Server 2000版中,default to local cursors 选项默认为 FALSE,以便与 SQL Server 早期版本中的内容匹配。
使用 DECLARE 和 OPEN 局部游标的存储过程可以将游标传递出去以供要求调用的存储过程、触发器或批处理使用。这可以通过使用由新的 CURSOR VARYING 数据类型定义的 OUTPUT 参数来实现。游标变量只能用作 OUTPUT 参数。不能将它们用于输入参数。当存储过程完成时游标必须是打开的,以便将游标返回 OUTPUT 参数。也可以通过新的 CURSOR 数据类型来声明局部变量以包含对局部游标的引用。
USE pubsGO/* Create a procedure with a cursor output parameter. */CREATE PROCEDURE OpenCrsr @OutCrsr CURSOR VARYING OUTPUT ASSET @OutCrsr = CURSOR FORSELECT au_lnameFROM authorsWHERE au_lname LIKE 'S%'OPEN @OutCrsrGO/* Allocate a cursor variable. */DECLARE @CrsrVar CURSOR/* Execute the procedure created earlier to fill the variable. */EXEC OpenCrsr @OutCrsr = @CrsrVar OUTPUT/* Use the variable to fetch the rows from the cursor. */FETCH NEXT FROM @CrsrVarWHILE (@@FETCH_STATUS <> -1)BEGIN FETCH NEXT FROM @CrsrVarENDCLOSE @CrsrVarDEALLOCATE @CrsrVarGO |
数据库 API 不支持存储过程中的游标输出参数。不能直接从数据库 API 函数执行包含游标输出参数的存储过程。而只能从另一个存储过程、触发器、Transact-SQL 批处理或脚本执行这些存储过程。
只有在明确释放时或关闭连接时 GLOBAL 游标才可用。创建 LOCAL 游标的存储过程、触发器或批处理终止时将隐性释放 LOCAL 游标,除非游标已作为参数返回。当调用过程的代码中引用游标的参数或变量超出作用域时,将隐性地释放 LOCAL 游标。