游标管理

  关系数据库中的操作作用与表中的所有数据行,SELECT语句返回的结果集由满足WHERE子句条件的所有行组成。应用程序并非总是能有效地把整个结果集作为一个单元来处理,他们需要一种机制类每次处理一行或几行,游标(Cursor)正是为结果集提供这种机制的工具。

一.游标概述

   游标是一种处理数据的方法,它可以对结果集进行逐行处理,也可以指向结果集中的任意位置,并对该位置的数据进行处理。

 1.游标种类

  SQL_Server 支持3中类型的游标:Transact-SQL游标、API服务器游标和客户游标。

1)Transact—SQL游标

Transact—SQL游标是由DECLARE CURSOR语句定义,主要用在服务器上,由从客户端发送给服务器的Transact—SQL语句或批处理、存储过程、触发器中的Transact—SQL语句进行管理。Transact—SQL游标不支持提取数据块或多行数据。

2)API游标

API游标支持再OLE DB、ODBC以及DB_library中使用游标函数,主要用在服务器上。每一次客户端应用程序调用API游标函数,SQL Server的OLE DB提供者、ODBC驱动器或DB——library的动态链接库(。dll)都会将这些客户请求送给服务器以对API游标进行处理。

3)客户游标

客户游标当客户机缓存结果集时才使用。在客户游标中,有一个默认的结果集被用来在客户机上缓存整个结果集。客户游标仅支持静态游标。一般情况下,服务器游标能支持绝大多数的游标操作,单不支持所有的Transact-SQL语句或批处理,所以客户游标常常仅被用作服务器游标的辅助。

 由于API游标和Transact-SQL游标使用在服务器端,所以被称为服务器游标或后台游标,而客户游标被称为前台游标。

2.服务器游标与默认结果集的比较

 SQL Server以两种方式为用户返回结果集:默认结果集和服务器游标。

(1)默认结果集具有的特点:开销小;取数据时提供最大性能;仅支持默认的单进、只读游标功能;返回结果行时一次一行;连接时一次只支持一个活动语句;支持所有Travsact-SQL语句。

(2)服务器游标具有的特点:支持所有游标功能;可以为用户返回数据块;在单个连接上支持多个活动语句;以性能补偿游标功能;不支持所有返回多于一行结果集的Transact-SQL语句。

使用游标不如使用默认结果集的效率高。在默认结果集中客户端只想服务器发送要执行的语句。而使用服务器游标时,每个FETCH语句都必须从客户端发往服务器,再在服务器中分析此语句并将它编译为执行计划。

如果一个Transact-SQL语句将返回一个相对小的结果集,此结果集可以存放在内存中共客户端应用程序使用,而且用户事先知道在执行此语句之前必须检索整个结果集,那么就使用默认结果集。只有在需要游标操作以支持应用程序的功能,或者可能只检索一部分结果集时,才使用服务器游标。

3.服务器游标与客户游标的比较

使用服务器游标比使用客户游标有以下几方面的优点。

(1)性能:如果要在游标中访问部分数据,使用服务器游标将提供最佳性能,因为只有被渠道的数据在网络上发送,客户游标在客户端存取所有结果集。

(2)更准确的定位更新:服务器游标直接支持定位操作,如UPDATE 和DELETE语句,客户游标通过产生Transact-SQL搜索UPDATE语句模拟定位游标更新,如果多行与UPDATE语句的WHERE子句的条件相匹配将导致无意义更新。

(3)内存使用:使用服务器游标时,客户端不需要高速存取大量数据或者保持有关游标位置的信息,这些都由服务器类完成。

(4)多活动语句:使用服务器游标时,结果不会存留在游标操作之间的连接上,这就允许同时拥有多个活动的基于游标的语句。

4.服务器游标类型

SQL Server支持4中类型的服务器游标,它们时单进游标、静态游标、动态游标和键集驱动游标。

(1)单进游标只支持游标按从前向后顺序提取数据,游标从数据库中提取一条记录并进行操作,操作完毕后,再提取下一条记录。

(2)静态游标也称为快照游标,它总是按照游标打开时的原样显示结果集,并不反映在数据库中对任何结果集成员所做的修改,因此不能利用静态游标修改基表中的数据。静态游标打开时的结果集存储在数据库tempdb中。静态游标始终是只读的。

(3)动态哟表也称为敏感游标,与静态游标相对,当游标在结果集中滚动时,结果集中的数据记录的数据值、顺序和成员的变化均反映到游标上,用户所做的各种操作均可通过游标反映。

(4)键集驱动游标介于静态游标和动态游标之间,兼有两者的特点。打开键集驱动游标后,游标中的成员和行顺序是固定的。键集驱动游标由一套唯一标识符控制,这些唯一标识符就是键集。用户对基表中的非关键值列插入数据或进行修改造成数据值的变化,在整个游标中都是可见的。键集驱动游标的键集在游标打开时建立在数据库tempdb中。

各种游标对资源的小号各不相同,静态游标虽然存储在tempdb中,但消耗的资源很少,而动态游标使用tempdb较少,但在滚动期间检测的变化多,消耗的资源更多。键集驱动游标介于两者之间,它能检测大部分的变化,但比动态游标消耗的资源少。在实际操作中,单进游标作为选项应用到静态游标、动态游标或键集驱动游标中,而不单独列出。

二.声明游标

SQLServer游标具有下面的处理过程。

(1)声明游标,定义其特性,如游标中的行是否可以被更新。

(2)执行Transact-SQL语句生成游标。

(3)在游标中检索要查看的行。从游标中检索一行或几行的操作称为取数据。向前或向后执行取数据操作来检索行的行为称为滚动。

(4)关闭游标。

  通常使用DECLARE CURSOR语句来声明一个游标,该语句接受基于SQL-92标准的语句和使用一组Transact-SQL扩展的语法。

 1.SQL-92游标定义格式

  语法格式如下:

 DECLARE  cursor_name[INSENSITIVE][SCROLL]CURSOR  

FOR select_statement

[FOR{READ ONLY|UPDATE[OF column_name[,...n]]}]

各选项含义如下:

(1)cursor_name:所定义的Transact-SQL服务器游标名称。

(2)INSENSITIVE:定义的游标使用查询结果集的临时复本,保存在tempdb数据库中,即定义静态游标。如果省略INSENSITIVE,则定义动态游标,对基表的修改都反映在后面的提取中。

(3)SCROLL:指定游标使用的提取选项,默认时为NEXT,其取值如下表所示。

SCROLL的取值
SCROLL选项 含义
FIRST 提取游标中的第一行数据
LAST         提取游标中的最后一行数据
PRIOR 提取游标当前位置的上一行数据
NEXT 提取游标当前位置的下一行数据
RELATIVE n 提取游标档期那位置之前或之后的第n行数据(n为正表是向后,n为负表是向前)
ABSULUTE n 提取游标中的第n行数据

(4)select_statement:定义游标结果集的SELECT语句,不能使用关键字COMPUTE、COMPUTE BY、FOR BROWSE 和INT

O

(5)READ ONLY:表示定义的游标为只读游标,禁止UPDATE、DELETE语句通过游标修改基表中的数据。

(6)UPDATE[OF column_name[,...n]]:指定游标内科修改的列,若未指定则所有列均可被修改。

举例:使用SQL-92标准的游标声明语句声明一个游标,用于访问Sales数据库中的goods表的信息。

USE Sales

GO

DECLARE Goods_cursor CURSOR

FOR

SELECT * FROM Goods

FOR READ ONLY

2.Transact-SQL扩展游标定义格式

语句格式如下:

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 column_name[,...n]]]

各选项的含义如下:

(1)LOCAL:定义游标的作用域仅限在其所在的批处理、存储过程或触发器中。当建立游标的批处理、存储过程、触发器执行结束后,游标被自动释放。

(2)GLOBAL:定义游标的作用域时整个会话层。会话层指用户的连接时间,包括从用户登陆SQL Server到脱离数据看看的时间段。选择GLOBAL表明在整个会话层的任何存储过程、触发器或批处理中都可以使用该游标,只有当用户脱离数据库时,该游标才会被自动释放。

(3)FORWARD_ONLY:指明游标为单进游标,只能从第一行滚动到最后一行。此时只能使用FETCH NEXT 操作。如果在指定FORWARD_ONLY时不指定STATIC、KEYSET和DYNAMIC关键字,则游标作为DYNAMIC游标进行操作。如果FORWARD_ONLY和SCROLL均未指定,处分指定STATIC、KEYSET或DYNAMIC关键字,否则默认为FORWARD_ONLY。STATIC、KEYSET和DYNAMIC游标默认为SCROLL。

(4)STATIC:定义静态游标,使用数据的临时备份。对游标的所有请求都从tempdb数据库的临时表中得到应答。因此,对基本表的修改不影响游标中的数据,也无法通过游标来更新基本表。

(5)KEYSET:定义键值驱动游标,指定在游标打开时,游标中列的顺序是固定的。唯一标识行的关键字集合在tempdb内形成表keyset。对基表中的非关键值的更改(由游标服务器产生或由其他用户提交)在用户滚动游标时是可视的。由其他用户插入的值是不可视的(不能通过Transact-SQL服务器游标插入)。

(6)DYNAMIC:定义动态游标,指明基本表的变化将反映到游标中。使用该选项会最大程度上保证数据的一致性,但需要大量的游标资源。

(7)FAST_FORWARD:指明一个单进只读型游标。此选项已为执行进行了优化。FAST_FORWARD和FORWARD_ONLY 互斥,两者任选其一。

(8)SCROLL_LOCKS:指明锁被放置在游标结果集所使用的数据上。当数据被读入游标中时,就会出现锁,以确保通过游标对基表进行的更新或删除操作被成功执行。

(9)OPTIMISTIC:指明在填充游标时不锁定基表中的数据行。在数据被读入游标后,如果游标中某行数据已改变,那么对游标数据进行更新或删除操作可能会导致失败。

(10)TYPE_WARNING:指明若游标类型被修改成与用户定义的类型不同时,将发送一个警告信息给客户端。

(11)cursor_name、select_statement、SCROLL、READ_ONLY、UPDATE[OF column_name[,...n]]的含义与SQL-92游标格式的含义相同。

举例:为customer表定义一个全局滚动动态游标,用于访问顾客的编号、姓名、地址、电话信息。

DECLARE cur_customer CURSOR

GLOBAL SCROLL DYNAMIC

FOR

SELECT customer_id,customer_name,address,telephone

FROM customer

三.使用游标

用DECLARE CURSOR定义了游标后,可以用OPEN语句打开游标,FETCH语句读取游标数据,CLOSE语句关闭游标,DEALLOCATE语句释放游标占用的相同资源。

1.打开游标

游标声明之后,必须打开才能使用。打开游标的语法格式如下:

OPEN{{[GLOBAL]cursor_name}|cursor_variable_name}

各选项的含义如下:

(1)GLOBAL:指定全局游标。

(2)cursor_name:已声明的游标名称。如果一个全局游标与一个局部游标同名,则使用GLOBAL声明其全局游标。

(3)cursor_variable_name:游标变量的名称,该名称可以引用一个游标。

如果游标是以STATIC选项声明的,即静态游标,OPEN语句将创建一个临时表 来放置结果集。如果游标是以KEYSET选项声明的,即键值驱动游标,OPEN将创建一个临时表来放置关键之。这些临时表都储存在tempdb数据库中。

打开游标的时候,服务器就执行SELECT语句,以寻找游标集合的成员并且安排游标集合的顺序。

例如:打开上例所声明的游标:

OPEN cur_customer

游标可以重复地关闭和打开。此时,游标选择语句要重新执行,以决定这个集合更新后的顺序和成员,且行指针移到集合的第一行。

游标打开之后,使用全局变量@@cursor_rows可以得到最后打开的游标中符合条件的行数。为了提高性能,SQL Server将启动另外一个独立的线程继续从基本表中读取数据行,从游标中读取数据的操作不必等到所以有符合条件的数据行都从基本表中读入游标再进行。

2.读取游标

一旦游标被成功打开,就可以从有博爱中逐行地读取数据,以进行相关处理。从游标中读取数据主要使用FECH命令。其语法格式如下:

FETCH

[[NEXT|PRIOR|FIRST|LAST

     |ABSOLUTE{n|@nvar}|RELATIVE{n|@nvar}]

  FROM]

{{[GLOBAL]cursor_name}|cursor+variable_name}

[INTO @variable_name[,...n]]

各选项的含义如下:

(1)NEXT、PRIOR、FIRST、LAST:分别返回当前行之后、当前行之前、第一行、最后一行,并且将其作为当前行。NEXT为默认的游标提取选项。

(2)ABSOLUTE{n|@nvar}:表示提取游标的第n行。如果n或@nvar为正数,则返回从游标头开始的第n行;如果n或@nvar为负数,则返回游标尾之前的第n行,并将返回的行作为当前行;如果n或@nvar为0,则没有行返回。n必须为整数常量,@nvar必须为smallint、tinyint或int。

(3)RELATIVBE{n|@nvar}:对n或@nvar的符号处理与ABSOLUTE选项相同,区别是RELATIVE以当前行为基础进行操作。

(4)INTO @variable_name[,...n]:允许将提取操作的列数据存放到局部变量中。列表中的各个变量从左到右与游标结果集中的相应列相关联,各变量的数据类型也要与结果列的数据类型匹配。

参数{[GLOBAL]cursor_name}|cursor_variable_name与OPEN语句的参数含义相同。

全局变量@@fetch_status返回最后一条FETCH语句的状态,每执行一条FETCH语句后,都应检查此变量,以确定上次FETCH操作是否成功。下表为该变量可能出现的3种状态值。

@@fetch_status变量
返回值 描述
0 FETCH命令已成功执行
-1 FETCH命令失败或者行数据已超出子结果集
-2 所读取的数据已经不存在

注意:

(1)如果游标定义了FORWARD_ONLY或FAST_FORWARD选项,则只能选择FETCH NEXT命令。

(2)如果游标未定义DYNAMIC、FORWARD_ONLY或FAST_FORWARD选项,而定义了KEYSET、STATIC或SCROLL中的某一个,则支持所有FETCH选项。

(3)DYNAMIC SCROLL支持除ABSOLUTE之外的所有FETCH选项。

举例:打开上例中声明的游标,读取游标中国的数据。

OPEN cur_customer

FETCH NEXT FROM cur_customer             /*取第一个数据行*/

WHILE @@fetch_status =0                       /*检查@@fetch_atstus是否还有数据可取*/

BEGIN

          FETCH NEXT FROM cur_customer

END

运行结果如图所示。

  customer_id customer_name address telephone
1 C001 东方体育用品公司 东方市中山路25号 7536802
         
  customer_id customer_name address telephone
1 C002 北京泛亚实业公司 长岭市五一路785号 68510231
         
  customer_id customer_name address telephone
1 C003 洞庭强华电器公司 滨海市洞庭大道278号 7605333

本例中,通过WHILE循环来读取游标的每一行数据库,WHILE循环每执行一次,循环体语句FETCH NEXT就从游标中读取一行数据。判断循环的条件是@@fetch_status全局变量的值是否为0,是则表示FETCH NEXT语句成功执行,可以继续循环,否则退出循环。

3.关闭游标

 在处理完游标中的数据之后,必须关闭游标来释放数据结果集和定位于数据记录上的锁。CLOSE语句关闭游标,但不释放游标占用的数据结构。CLOSE的语法格式如下:

CLOSE{{[GLOBAL]cursor_name}|cursor_variable_name}

其参数与OPEN语句的参数含义相同。

例如,关闭上例中的游标cur_customer的命令:

CLOSE cur_customer

游标 cur_customer在关闭后,仍可用OPEN语句打开继续读取数据行。

4.释放游标

在使用游标时,各种针对游标的操作都要引用游标名,或者引用指向游标的游标变量。当CLOSE命令关闭游标时,并没有释放游标占用的数据结构。因此常用DEALLOCATE命令删除游标与游标名或游标变量之间的练习,并且释放游标占用的所有系统资源。其语法格式如下:

DEALLOCATE{{[GLOBAL]cursor_name}|cursor_variable_name}

其参数与OPEN语句的参数含义相同。

一旦某个游标被删除,在重新打开之前,必须再次对其进行声明。

例如,释放上例所定义的游标cur_customer:

DEALLOCATE cur_customer

DEALLOCATE cursor_variable_name语句只删除对游标命名变量的引用。直到批处理、存储过程或触发器结束时变量离开作用域,才释放变量。

















猜你喜欢

转载自blog.csdn.net/geyulei/article/details/80738433