游标概述
游标(cursor)是系统为用户开设的一个数据缓冲区,存放SQL 语句的执行结果.
游标允许应用程序对查询语句select 返回的行结果集中每一行进行相同或不同的操作,而不是一次对整个结果集进行同一种操作。它还提供对基于游标位置而对表中数据进行删除或更新的能力.
游标把作为面向集合的数据库管理系统和面向行的程序设计两者联系起来,使两个数据处理方式能够进行沟通。
三种类型的游标:Transact_SQL游标,API 服务器游标和客户游标。
Transact_SQL 游标
Transact_SQL游标是由DECLARECURSOR 语法定义、主要用在Transact_SQL 脚本、存储过程和触发器中。Transact_SQL 游标主要用在服务器上,由从客户端发送给服务器的Transact_SQL 语句或是批处理、存储过程、触发器中的Transact_SQL 进行管理。Transact_SQL游标不支持提取数据块或多行数据。
API 服务器游标
API 游标支持在OLE DB, ODBC 以及DB_library 中使用游标函数,主要用在服务器上。每一次客户端应用程序调用API 游标函数,MS SQLSEVER 的OLE DB 提供者、ODBC 驱动器或DB_library的动态链接库(DLL)都会将这些客户请求传送给服务器以对API 游标进行处理。
客户游标
客户游标主要是当在客户机上缓存结果集时才使用。在客户游标中,有一个缺省的结果集被用来在客户机上缓存整个结果集。客户游标仅支持静态游标而非动态游标。由于服务器游标并不支持所有的Transact-SQL 语句或批处理,所以客户游标常常仅被用作服务器游标的辅助。因为在一般情况下,服务器游标能支持绝大多数的游标操作。由于API 游标和Transact-SQL 游标使用在服务器端,所以被称为服务器游标,也被称为后台游标,而客户端游标被称为前台游标。
游标的组成:
每一个游标必须有四个组成部分这四个关键部分必须符合下面的顺序;
1. DECLARE 游标
2. OPEN 游标
3.从一个游标中FETCH 信息
4. CLOSE 游标
5. DEALLOCATE 游标
Declare 游标
如果使用Transcat-SQL 来创建游标,一个游标有两个重要的部分:游标结果集和游标的位置,在声明游标时你必须同时定义将要在你的所有的游标操作中使用的结果集.通常我们使用DECLARE 来声明一个游标声明一个游标主要包括以下主要内容:
游标名字数据来源(表和列)
选取条件属性(仅读或可修改)
语法格式:
DECLARE cursor_name [INSENSITIVE][SCROLL] CURSOR
FOR select_statement
[FOR {READ ONLY | Update [OFcolumn_name [,...n]]}]
参数详解:
(1)、cursor_name:指游标的名字。
(2)、INSENSITIVE:表明MS SQLSERVER 会将游标定义所选取出来的数据记录存放在一临时表内(建立在tempdb 数据库下)。对该游标的读取操作皆由临时表来应答。因此,对基本表的修改并不影响游标提取的数据,即游标不会随着基本表内容的改变而改变,同时也无法通过游标来更新基本表。如果不使用该保留字,那么对基本表的更新、删除都会反映到游标中。另外应该指出,当遇到以下情况发生时,游标将自动设定INSENSITIVE 选项。在Select 语句中使用DISTINCT、 GROUPBY、 HAVING UNION 语句;使用OUTER JOIN;所选取的任意表没有索引;将实数值当作选取的列
(3)、SCROLL:表明所有的提取操作(如FIRST、 LAST、 PRIOR、 NEXT、 RELATIVE、ABSOLUTE)都可用。如果不使用该保留字,那么只能进行NEXT 提取操作。由此可见,SCROLL极大地增加了提取数据的灵活性,可以随意读取结果集中的任一行数据记录,而不必关闭再重开游标。
(4)、select_statement:是定义结果集的Select 语句。应该注意的是,在游标中不能使用COMPUTE、COMPU-TE BY、 FOR BROWSE、 INTO 语句。
(5)、READONLY:表明不允许游标内的数据被更新尽管在缺省状态下游标是允许更新的。而且在Update 或Delete 语句的WhereCURRENT OF 子句中,不允许对该游标进行引用。
(6)、Update[OF column_name[,n]]:定义在游标中可被修改的列,如果不指出要更新的列,那么所有的列都将被更新。当游标被成功创建后,游标名成为该游标的惟一标识,如果在以后的存储过程、触发器或Transact_SQL 脚本中使用游标,必须指定该游标的名字。
DEMO:
declare cursor_time cursor
for
select clock_id,emp_id,sign_time
from timerecords
where emp_id = 'P0802604'
and convert(char(10),sign_time,121) ='2011-06-10'
上面介绍的是SQL_92 的游标语法规则。下面介绍MS SQL SERVER 提供的扩展了的游标声明语法,通过增加另外的保留字,使游标的功能进一步得到了增强其语法规则:
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 columen_name[,…n]]
(1)、LOCAL:定义游标的作用域仅限在其所在的存储过程、触发器或批处理中。当建立游标的存储过程执行结束后,游标会被自动释放。因此,我们常在存储过程中使用OUTPUT保留字,将游标传递给该存储过程的调用者,这样在存储过程执行结束后,可以引用该游标变量,在该种情况下,直到引用该游标的最后一个就是被释放时,游标才会自动释放。
(2)、GLOBAL:定义游标的作用域是整个会话层,指用户的连接时间它包括从用户登录到SQLSERVER 到脱离数据库的整段时间。选择GLOBAL 表明在整个会话层的任何存储过程、触发器或批处理中都可以使用该游标,只有当用户脱离数据库、时该游标才会被自动释放。注意:如果既未使用GLOBAL 也未使用LOCAL,那么SQLSERVER 将使用default local cursor数据库选项,为了与以前的版本兼容,该选项常设置为FALSE。
(3)、FORWARD_ONLY:选项指明在从游标中提取数据记录时,只能按照从第一行到最后一行的顺序,此时只能选用FETCH NEXT 操作。除非使用STATIC, KEYSET 和DYNAMIC 关键字,否则如果未指明是使用FORWARD_ONLY 还是使用SCROLL,那么FORWARD_ONLY为缺省选项,因为若使用STATIC, KEYSET 和DYNAMIC 关键字,则变成了SCROLL 游标。另外如果使用了FORWARD_ONLY,便不能使用FAST_FORWARD。
(4)、STATIC:选项的含义与INSENSITIVE选项一样,MS SQLSERVER 会将游标定义所选取出来的数据记录存放在一临时表内(建立在tempdb 数据库下)。对该游标的读取操作皆由临时表来应答。因此对基本表的修改并不影响游标中的数据,即游标不会随着基本表内容的改变而改变,同时也无法通过游标来更新基本表。
(5)、KEYSET:指出当游标被打开时,游标中列的顺序是固定的,并且MS SQL SERVER 会在tempdb 内建立一个表,该表即为KEYSET 的键值可惟一识别游标中的某行数据。当游标拥有者或其它用户对基本表中的非键值数据进行修改时,这种变化能够反映到游标中,所以游标用户或所有者可以通过滚动游标这显示这些数据。
当其它用户增加一条新的符合所定义的游标范围的数据时,无法由此游标读到该数
据。因为Transact-SQL 服务器游标不支持INSERT 语句。
如果在游标中的某一行被删除掉,那么当通过游标来提取该删除行时,@@FETCH_STATUS 的返回值为-2。@@FETCH_STATUS 是用来判断读取游标是否成功的系统全局变量。
由于更新操作包括两部分:删除原数据、插入新数据,所以如果读取原数据,@@FETCH_STATUS 的返回值为-2;而且无法通过游标来读取新插入的数据。但是如果使用了WHERE CURRENTOF 子句时,该新插入行数据便是可见的。
注意:如果基础表未包含惟一的索引或主键,则一个KEYSET 游标将回复成STATIC 游标。
(6)、DYNAMIC:指明基础表的变化将反映到游标中,使用这个选项会最大程度上保证数
据的一致性。然而,与KEYSET 和STATIC 类型游标相比较,此类型游标需要大量的游标资源。
(7)、FAST_FORWARD:指明一个FORWARD_ONLY,READ_ONLY 型游标。此选项已为执行进行了优化。如果SCROLL 或FOR_UPDATE 选项被定义,则FAST_FORWARD选项不能被定义。
(8)、SCROLL_LOCKS:指明锁被放置在游标结果集所使用的数据上。数据被读入游标中时,就会出现锁。这个选项确保对一个游标进行的更新和删除操作总能被成功执行。如果FAST_FORWARD 选项被定义,则不能选择该选项。另外,由于数据被游标锁定,所以当考虑数据并发处理时,应避免使用该选项。
(9)、OPTIMISTIC:指明在数据被读入游标后,如果游标中某行数据已发生变化,那么对游标数据进行更新或删除可能会导致失败。如果使用了FAST_FORWARD 选项,则不能使用该选项。
(10)、TYPE_WARNING:指明若游标类型被修改成与用户定义的类型不同时,将发送一个警告信息给客户端。注意:不可以将SQL_92 的游标语法规则与MS SQLSERVER 的游标扩展用法混合在一起使用。
声明游标时应注意的一些问题:
如果在CURSOR 前使用了SCROLL 或INSENSITIVE保留字,则不能在CURSOR 和FOR
select_statement 之间使用任何的保留字。反之同理。
如果用DECLARE CURSOR 声明游标时,没有选择READ_ONLY、 OPTIMISTIC 或
SCROLL_LOCKS 选项时,游标的缺省情况为:
如果SELECT 语句不支持更新,则游标为READ_ONLY;
STATIC 和FAST_FORWARD 类型的游标缺省为READ_ONLY;
DYNAMIC 和KEYSET 游标缺省为OPTIMISTIC。
我们仅能在Transact-SQL 语句中引用游标,而不能在数据库API 函数中引用。
游标被声明以后,可以通过系统过程对其特性进行设置。
对那些有权限对视图、表或某些列执行SELECT 语句的用户而言,它也具有使用游
标的缺省权限。
DEMO1:标准游标
declare cur_time cursor
for
select clock_id,emp_id,sign_time
from timerecords
DEMO2:只读游标
declare cur_time1 cursor
for
select clock_id,emp_id,sign_time
from timerecords
for read only
DEMO3:更新游标
declare cur_time2 cursor
for
select clock_id,emp_id,sign_time
from timerecords
for update
打开游标:
游标在声明以后,如果要从游标中读取数据必须打开游标。打开一个Transact-SQL 服务器游标使用OPEN 命令,其语法规则为:
OPEN { { [GLOBAL] cursor_name } |cursor_variable_name}
参数:
(1)、GLOBAL:定义游标为一全局游标。
(2)、cursor_name:声明的游标名字。如果一个全局游标和一个局部游标都使用同一个游标名,则如果使用GLOBAL 便表明其为全局游标,否则表明其为局部游标。
(3)、cursor_variable_name:为游标变量。当打开一个游标后时,MS SQL SERVER 首先检查声明游标的语法是否正确,如果游标声明中有变量,则将变量值带入。在打开游标时,如果游标声明语句中使用了INSENSITIVE 或STATIC 保留字,则OPEN 产生一个临时表来存放结果集;如果在结果集中任何一行数据的大小超过MS SQLSERVER 定义的最大行尺寸时,OPEN 命令将失败;如果声明游标时作用了KEYSET 选项,则OPEN 产生一个临时表来存放键值。所有的临时表都存在tempdb 数据库中。在游标被成功打开之后,@@CURSOR_ROWS 全局变量将用来记录游标内数据行数。为了提高性能,MS SQL SERVER 允许以异步方式从基础表向KEYSET 或静态游标读入数据,即如果MS SQL SERVER 的查询优化器估计从基础表中返回给游标的数据行已经超过sp_configurecursor threshold 参数值,则MS SQL SERVER 将启动另外一个独立的线程来继续从基础表中读入符合游标定义的数据行,此时可以从游标中读取数据进行处理而不必等到所有的符合游标定义的数据行都从基础表中读入游标 @@CURSOR_ROWS 变量存储的正是在调用@@CURSOR_ROWS 时,游标已从基础表读入的数据行。
@@CURSOR_ROWS 的返回值有以下四个,如表所示:
如果所打开的游标在声明时带有SCROLL 或INSENSITIVE保留字,那么@@CURSOR_ROWS
的值为正数且为该游标的所有数据行。如果未加上这两个保留字中的一个,则
@@CURSOR_ROWS 的值为-1,说明该游标内只有一条数据记录。
DEMO:
declare cur_time3 cursor
for
select clock_id,emp_id,sign_time
from timerecords
where emp_id = 'P0802604'
OPEN cur_time3 --打开游标
GO
从游标中读取数据
当游标被成功打开以后,就可以从游标中逐行地读取数据,以进行相关处理。从游标
中读取数据主要使用FETCH 命令。其语法规则为:
FETCH
[ [ NEXT|PRIOR|FIRST|LAST
|ABSOLUTE{n|@nvar}
|RELATIVE{n|@nvar}]
FROM]
{{[GLOBAL]cursor_name}|@cursor_variable_name}
[INTO @variable_name[,…n]]
参数说明:
(1)、NEXT:返回结果集中当前行的下一行,并增加当前行数为返回行行数。如果FETCHNEXT 是第一次读取游标中数据,则返回结果集中的是第一行而不是第二行。
(2)、PRIOR:返回结果集中当前行的前一行,并减少当前行数为返回行行数。如果FETCHPRIOR 是第一次读取游标中数据,则无数据记录返回,并把游标位置设为第一行。
(3)、FIRST:返回游标中第一行。
(4)、LAST:返回游标中的最后一行。
(5)、ABSOLUTE{n | @nvar}:如果n 或@nvar 为正数,则表示从游标中返回的数据行数。如果n 或@nvar 为负数,则返回游标内从最后一行数据算起的第n 或@nvar 行数据。若n 或@nvar 超过游标的数据子集范畴,则@@FETCH_STARS 返回-1,在该情况下,如果n或@nvar 为负数,则执行FETCH NEXT 命令会得到第一行数据,如果n 或@nvar 为正值,执行FETCHPRIOR 命令则会得到最后一行数据。n 或@nvar 可以是一固定值也可以是一smallint,tinyint 或int 类型的变量。
(6)、RELATIVE{n | @nvar}:若n 或@nvar 为正数,则读取游标当前位置起向后的第n 或@nvar 行数据;如果n 或@nvar 为负数,则读取游标当前位置起向前的第n 或@nvar行数据。若n 或@nvar 超过游标的数据子集范畴,则@@FETCH_STARS 返回-1,在该情况下,如果n 或@nvar 为负数,则执行FETCH NEXT 命令则会得到第一行数据;如果n 或@nvar为正值,执行FETCHPRIOR 命令则会得到最后一行数据。n 或@nvar 可以是一固定值也可以是一smallint,tinyint 或int 类型的变量。
(7)、INTO@variable_name[,...n]:允许将使用FETCH 命令读取的数据存放在多个变量中。在变量行中的每个变量必须与游标结果集中相应的列相对应,每一变量的数据类型也要与游标中数据列的数据类型相匹配。@@FETCH_STATUS 全局变量返回上次执行FETCH 命令的状态。在每次用FETCH 从游标中读取数据时,都应检查该变量,以确定上次FETCH 操作是否成功,来决定如何进行下一步处理。@@FETCH_STATUS 变量有三个不同的返回值,如表:
在使用FETCH 命令从游标中读取数据时,应该注意以下的情况:
当使用SQL-92 语法来声明一个游标时,没有选择SCROLL 选项时,只能使用FETCH
NEXT 命令来从游标中读取数据,即只能从结果集第一行按顺序地每次读取一行,
由于不能使用FIRST、 LAST、 PRIOR,所以无法回滚读取以前的数据。如果选择
了SCROLL 选项,则可能使用所有的FETCH 操作。
当使用MS SQL SERVER 的扩展语法时,必须注意以下约定:
如果定义了FORWARD-ONLY 或FAST_FORWARD选项,则只能使用FETCHNEXT
命令;
如果没有定义DYNAMIC,FORWARD_ONLY 或FAST_FORWARD 选项,而定义了
KEYSET, STATIC 或SCROLL 中的任何一个,则可使用所有的FETCH 操作;
DYNAMIC SCROLL 游标支持所有的FETCH,选项但禁用ABSOLUTE 选项。
DEMO:
use demo_db
go
declare cur_time3 cursor
for
select clock_id,emp_id,sign_time
from timerecords
where emp_id = 'P0802604'
OPEN cur_time3 --打开游标
GO
FETCH NEXT FROM cur_time3 --执行取数操作
WHILE @@FETCH_STATUS=0 --检查@@FETCH_STATUS,以确定是否还可以继续取数
BEGIN
FETCH NEXT FROM cur_time3
END
--返回结果:
关闭游标
(1)、使用CLOSE 命令关闭游标
在处理完游标中数据之后必须关闭游标来释放数据结果集和定位于数据记录
上的锁。CLOSE 语句关闭游标,但不释放游标占用的数据结构。如果准备在随后的使用中再次打开游标,则应使用CLOSE 命令。其关闭游标的语法规则为:
CLOSE { { [GLOBAL] cursor_name } |cursor_variable_name }
DEMO:
use demo_db
go
declare cur_time3 cursor
for
select clock_id,emp_id,sign_time
from timerecords
where emp_id = 'P0802604'
OPEN cur_time3 --打开游标
GO
FETCH NEXT FROM cur_time3 --执行取数操作
WHILE @@FETCH_STATUS=0 --检查@@FETCH_STATUS,以确定是否还可以继续取数
BEGIN
FETCH NEXT FROM cur_time3
END
close cur_time3 --关闭游标
(2)、自动关闭游标
我们已经了解到游标可应用在存储过程、触发器和Transact_SQL 脚本中。如果在
声明游标与释放游标之间使用了事务结构,则在结束事务时游标会自动关闭。其具体的情
况如下所示:
○1 、声明一个游标
○2 、打开游标
○3 、读取游标
○4 、BEGINTRANSATION
○5 、数据处理
○6 、COMMITTRANSATION
○7 、回到步骤3
在这样的应用环境中。当从游标中读取一条数据记录进行以BEGINTRANSATION为开头,COMMIT TRANSATION 或ROLLBACK 为结束的事务处理时,在程序开始运行后,第一行数据能够被正确返回,经由步骤7,程序回到步骤3,读取游标的下一行,此时常会发现游标未打开的错误信息。其原因就在于当一个事务结束时,不管其是以COMMITTRANSATION 还是以ROLLBACK TRANSATION 结束,MS SQL SERVER 都会自动关闭游标,所以当继续从游标中读取数据时就会造成错误。
解决这种错误的方法就是使用SET 命令将CURSOR_CLOSE_ON_COMMIT这一参数设置为OFF 状态。其目的就是让游标在事务结束时仍继续保持打开状态,而不会被关闭。使用SET命令的格式为:
SET CURSOR_CLOSE_ON_COMMIT OFF
释放游标
在使用游标时,各种针对游标的操作或者引用游标名,或者引用指向游标的游标变量。当CLOSE 命令关闭游标时,并没有释放游标占用的数据结构。因此常使用DEALLOCATE 命令。通过该命令可以删除掉游标与游标名或游标变量之间的联系,并且释放游标占用的所有系统资源。其语法规则为:
DEALLOCATE { { [GLOBAL] cursor_name }| @cursor_variable_name}
当使用DEALLOCATE@cursor_variable_name 来删除游标时,游标变量并不会被释
放,除非超过使用该游标的存储过程、触发器的范围(即游标的作用域)。
DEMO:
use demo_db
go
declare cur_time3 cursor
for
select clock_id,emp_id,sign_time
from timerecords
where emp_id = 'P0802604'
OPEN cur_time3 --打开游标
GO
FETCH NEXT FROM cur_time3 --执行取数操作
WHILE @@FETCH_STATUS=0 --检查@@FETCH_STATUS,以确定是否还可以继续取数
BEGIN
FETCH NEXT FROM cur_time3
END
close cur_time3
deallocate cur_time3 --释放游标
游标变量
在批处理或过程的正文中用DECLARE 语句声明变量,并用SET 或SELECT 语句给其指派值。游标变量可通过该语句声明,并且可用在其他与游标相关的语句中。所有变量在声明后均初始化为NULL。
首先创建一个游标并打开该游标,之后创建一个游标变量并将游标的值(SELECT *FROMJobs)赋给游标变量,并通过FETCH 语句读取游标变量中的值,最后关闭并释放游标。
DEMO:
declare cur_time3 cursor --创建游标
for
select clock_id,emp_id,sign_time
from timerecords
where emp_id = 'P0802604'
OPEN cur_time3 --打开游标
DECLARE @CursorVar Cursor --创建游标变量
SET @CursorVar = cur_time3 --为游标变量赋值
FETCH NEXT FROM @CursorVar --读取游标变量中的值
CLOSE cur_time3 --关闭游标
DEALLOCATE cur_time3 --释放游标
几种游标的类型
A、静态游标
静态游标的完整结果集在游标打开时建立在tempdb 中。静态游标总是按照游标打开时的原样显示结果集。静态游标在滚动期间很少或根本检测不到变化,虽然它在tempdb 中存储了整个游标,但消耗的资源很少。尽管动态游标使用tempdb 的程度最低,在滚动期间它能够检测到所有变化,但消耗的资源也更多。键集驱动游标介于二者之间,它能检测到大部分的变化,但比动态游标消耗更少的资源。
B、动态游标
动态游标与静态游标相对。当滚动游标时,动态游标反映结果集中所做的所有更改。结果集中的行数据值、顺序和成员在每次提取时都会改变。所有用户做的全部UPDATE、INSERT和DELETE 语句均通过游标可见。
C、只进游标
只进游标不支持滚动,它只支持游标从头到尾顺序提取。只在从数据库中提取出来后才能行检索。对所有由当前用户发出或由其他用户提交、并影响结果集中的行的INSERT、UPDATE 和DELETE 语句,其效果在这些行从游标中提取时是可见的。
D、键集驱动游标
打开游标时,键集驱动游标中的成员和行顺序是固定的。键集驱动游标由一套被称为键集的惟一标识符(键)控制。键由以惟一方式在结果集中标识行的列构成。
开时来自所有适合SELECT 语句的行中的一系列键值。键集驱动游标的键集在游标打开时建立在tempdb 中。对非键集列中的数据值所做的更改(由游标所有者更改或其他用户提交)在用户滚动游标时是可见的。在游标外对数据库所做的插入在游标内是不可见的,除非关闭并重新打
开游标。
使用游标修改及删除数据:
通常情况下我们用游标来从基础表中检索数据,以实现对数据的行处理。但在某些情况下,我们也常要修改游标中的数据,即进行定位更新或删除游标所包含的数据。所以必须执行另外的更新或删除命令,并在WHERE 子句中重新给定条件才能修改到该行数据。但是如果在声明游标时使用了FOR UPDATE 语句,那么就可以在UPDATE 或DELETE 命令中以WHERECURRENT OF 关键字直接修改或删除当前游标中所存储的数据,而不必使用WHERE 子句重新给出指定条件。当改变游标中数据时,这种变化会自动地影响到游标的基础表。但是如果在声明游标时选择了INSENSITIVE 选项时,该游标中的数据不能被修改。
使用游标修改数据
语法:
UPDATE table_name
SET column_name1={expression1 |NULL(select_statement)}
[,column_name2={expression2 |NULL(select_statement)}
WHERE CURRENT OF cursor_name
参数:
其中:
table_name: UPDATE 的表名;
column_name: UPDATE 的列名;
cursor_name:游标名。
DEMO:使用游标更新表orders
--1、查看表orders 原始数据:
select * from orders
返回:
--2、创建变量并附值,将变量@docno 做为更改的条件
Declare @docno char(20) /*声明变量*/
declare @docnos char(20)
declare @cust nchar(200)
declare @carrency char(3)
set @docno='a01' --为变量赋值
--3、创建游标并更新数据
DECLARE orders_cursor CURSOR --声明游标
FOR SELECT docno,cust,carrency FROMorders
OPEN orders_cursor --打开游标
FETCH NEXT FROM orders_cursor --获取游标的下一行数据
into @docnos ,@cust ,@carrency --使变量获得当前游标指定行的客户代码、客户名称及区域WHILE @@FETCH_STATUS = 0 --FETCH语句执行成功
BEGIN
if @docno=@docnos --判断变量的值是否与游标指定的客户代码相等
begin
--更新指定条件的carrency值为‘EN‘
update orders set carrency ='EN' wheredocno = @docnos
end
FETCH NEXT FROM orders_cursor --获取游标的下一行
into @docnos ,@cust ,@carrency --使变量获得当前游标指定行的客户代码、客户名称及区域
End
CLOSE orders_cursor --关闭游标
DEALLOCATE orders_cursor --释放游标
--4、查看表orders 更新后的信息
SELECT * FROM orders --重新选择操作员信息表
返回:
同之前查询的结果进行对比,可以看到,列docno 值等于a01 的列carrency值由原来的CH 更新为EN
使用游标删除数据
Transact-SQL 脚本、存储过程和触发器可以使用DELETE 语句中的WHERECURRENT OF 子句
删除它们当前所处的游标行。
语法:
Delete table_name
SET column_name1-{expression1|NULL(select_statement)}
[,column_name2={expression2|NULL(select_statement)}
WHERE CURRENT OF cursor_name
DEMO:
--1、声明变量并附值
Declare @docno char(20) /*声明变量*/
declare @docnos char(20)
declare @cust nchar(200)
declare @carrency char(3)
set @docno='a01' --为变量赋值
--2、创建游标
DECLARE delete_cursor Cursor --声明游标
For SELECT docno,cust,carrency FROMorders
--3、打开游标
OPEN delete_cursor --打开游标
--4、读取游标中的数值,当满足条件时,删除相应数据
FETCH NEXT FROM delete_cursor --获取游标的下一行
--使变量获得当前游标指定行的客户代码、客户名称及区域
into @docnos ,@cust ,@carrency
WHILE @@FETCH_STATUS = 0 --FETCH语句执行成功
BEGIN
if @docno=@docnos --判断变量的值是否与游标指定的客户代码相等
BEGIN
--删除指定条件的数据
DELETE orders WHERE docno = @docnos
END
FETCH NEXT FROM delete_cursor --获取游标的下一行
--使变量获得当前游标指定行的客户代码、客户名称及区域
into @docnos ,@cust ,@carrency
END
CLOSE delete_cursor --关闭游标
DEALLOCATE delete_cursor --释放游标
--5、查看表orders 更新后的信息
SELECT * FROM orders --重新选择操作员信息表
返回:
对比之前的输出结果,可以看到,docno 值等于a01 的行数据已被删除
将游标中的数据进行排序显示
在DECLARE CURSOR 语句中,将ORDER BY子句添加到查询中使游标数据排序。
ORDERY BY 子句语法:
ORDER BY <column name> [ ASC |DESC ]
[ ,...<last column name> [ ASC |DESC ]]
注意:与非游标的SELECT 语句中的ORDER BY子句不同,只有在查询的SELECT 子句中列出的供显示的列才能作为ORDER BY 子句中的列出现(在非游标的SELECT 语句中,表中任何在查询的FROM 子句中列出的列都可能出现在ORDER BY 子句中,即使列没有在SELECT子句中)。
DEMO:
use demo_db
go
DECLARE timer_cursor CURSOR
FOR SELECT clock_id,emp_id,sign_time
FROM timerecords
ORDER BY clock_id DESC
OPEN timer_cursor
FETCH NEXT FROM timer_cursor
WHILE @@FETCH_STATUS = 0
FETCH NEXT FROM timer_cursor
CLOSE timer_cursor
DEALLOCATE timer_cursor
游标应用:
游标常被应用在存储过程、触发器中
使用sp_helptext 查看存储过程sys.sp_cursor_list
-- Creation of sp_cursor_list
create procedure sys.sp_cursor_list
(
@cursor_return CURSOR VARYING OUTPUT,
@cursor_scope int
)
AS
if (@cursor_scope < 1) OR(@cursor_scope > 3)
begin
/* Raise an error: ?The value ofparameter is invalid? */
raiserror ( 16902, 1,1,N'sys.sp_cursor_list', N'@cursor_scope')
return (1)
end
if ( @cursor_scope < 3)
begin
set @cursor_return = CURSOR LOCALSCROLL DYNAMIC FOR
SELECT reference_name, cursor_name,cursor_scope,
status, model, concurrency,scrollable,
open_status, cursor_rows,fetch_status,
column_count, row_count,last_operation,
cursor_handle
FROM sys.syscursorrefs scr,sys.syscursors sc
WHERE scr.cursor_scope = @cursor_scopeAND
scr.cursor_handl = sc.cursor_handle
FOR READ ONLY
end
else
begin
set @cursor_return = CURSOR LOCALSCROLL DYNAMIC FOR
SELECT reference_name, cursor_name,cursor_scope,
status, model, concurrency,scrollable,
open_status, cursor_rows,fetch_status,
column_count, row_count,last_operation,
cursor_handle
FROM sys.syscursorrefs scr,sys.syscursors sc
WHERE scr.cursor_handl =sc.cursor_handle
FOR READ ONLY
end
open @cursor_return
在该存储过程中,@cursor_return 为一游标变量,并将其结果集返回给其调用者,该结果集保存有当前所有游标的各属性值。
注:在存储过程中,如果被定义为游标类型的变量使用OUTPUT 选项,则必须使用VARYING保留字,即为@variableCURSOR VARYING OUTPUT 形式。
总结游标:
游标作用:对select 筛选出的结果集进行逐行、遍历、多行操作。
用法:
--1、声明 declare 游标名 cursorfor select(语句)
--这是只进游标,只能使用fetch next 操作。
declare 游标名 scoll cursorfor select(语句)
--这是滚动游标,可以随意操作。
--2、打开 open 游标名
--3、使用:
fetch next from 游标名 into 变量名//下一
fetch prior from 游标名 into 变量名 //前一
fetch first from 游标名 into 变量名 //第一
fetch prior from 游标名 into 变量名 //前一
fetch absolute n from 游标名 into 变量名 //第n 行
fetch relative n from 游标名 into 变量名 //相对当前行第n 行
--4、关闭游标 close 游标名称
--5、释放游标 deallocate 游标名称
其它:
*1、伴随事务的使用
*2、伴随存储过程使用