11-1 游 标概 述
11-2 声 明游 标
11-3 打 开 游 标
11-4 提取游 标数 据
11-5 关闭释 放游 标
11-6 游 标 的 应 用在 SQL Server数据库中,游标是一个比较重要的概念,能提供这种机制对结果集的部分行记录进行处理。
本章主要介绍了游标的概念、分类、定义、嵌套以游标的打开、存取、定位、修改、删除、关闭、释放等操作。
第 11章 游标在 SQL Server数据库中,游标是一个比较重要的概念,能提供这种机制对结果集的部分行记录进行处理。本章主要介绍了游标的概念、分类、定义、嵌套以游标的打开、存取、定位、修改、删除、关闭、释放等操作。
在 SQL Server 2000系统数据库开发过程中,执行 SELECT 语句可进行查询并返回满足 WHERE 等子句中条件的所有数据的记录,这一完整的记录集称为行结果集。由于应用程序并不能总将整个结果集作为一个单元来有效地处理,因而往往需要某种机制,以便每次处理时可从某一结果集中逐一地读取一条或一部分行记录。游标( Cursor)能提供这种机制对结果集的部分行记录进行处理,不但允许定位在结果集的特定行记录上,而且还可从结果集的 当前位置检索若干条行记录,并可实施对相应的数据修改。
1,游标在 SQL Server数据库中,游标是一个比较重要的概念,游标总是与一条
Transact-SQL选择语句相关联。
定义:游标是一种处理数据的方法,它可对结果集进行逐行处理,可将游标视作一种指针,用于指向并处理结果集任意位置的数据。就本质而言游标提供了一种对从表中检索出的数据进行操作的灵活手段,由于游标由结果集和结果集中指向特定记录的游标位置组成,当决定对结果集进行处理时,必须声明定义一个指向该结果集的游标。
11-1 游标概述
1 允许程序对由查询语句 select返回的记录行集合中的每一行执行相同或不同的操作,而不是对整个行集合执行同一个操作。
1 提供对基于游标位置的表中记录行进行删除和更新的能力。
1 游标实际上作为面向集合的数据库管理系统( DBMS)和面向行的程序设计之间的桥梁,使这两种处理方式通过游标沟通起来。
SQL Server是一个关系数据库管理系统( RDBMS),游标的特点表明系统并没有一种描述表中单一记录的表达形式,除非使用 where 子句来强行选择被选中的一条记录,因此我们必须借助于游标来进行面向单条记录的数据处理。游标允许应用程序对 select查询语句返回的行结果集中每一行记录进行相同或不同的操作,而不是一次对整个结果集进行同一种操作。它还提供基于游标位置而对表中数据进行删除、更新的能力,可为由其他用户对显示在结果集中的数据库数据所做的更改提供不同级别的可见性支持。
SQL Server 2000下的游标可以分为三类,Transact_SQL 游标,API 服务器游标和客户机游标。
( 1) Transact_SQL 游标 。 Transact_SQL 游标是由 SQL Server服务器实现的游标,它的具体控制和管理通过脚本程序、存储过程和触发器将
Transact_SQL 语句传给服务器来完成。
( 2) API 游标 。声明 (Declare):为执行某操作声明一个游标打开 (Open),打开这个一个游标空否?,直到全部行处理完为止游 标 具有如下特点,
API( 数 据 库应 用程序接口)游 标 支持在 ADO,ODBC,OLE DB以及
DB_library 中使用游 标 函 数,主要用在服 务 器上,每一次客 户 端 应 用程序 调 用
API游 标 函 数,SQL Server 的 ADO,OLE DB 提供者,ODBC驱动 器或
DB_library 的 动态链 接 库 DLL 都 会将这 些客 户请 求 传 送 给 服 务 器以 对 API游 标进 行 处 理。
( 3)客 户 机游 标 。 客 户 机游 标 是 当 在客 户 机上 缓 存 结 果集 时 才使用 静态 游 标,
是一 种临时 性的游 标应 用方法。在客 户 机游 标 建立在客 户 机的 数 据集上,有一个 缺省的 结 果集被用 来 在客 户 机上 缓 存整 个结 果集,客 户 游 标 常常 仅 被用作
Transact_SQL 游 标与 API 游 标 的 辅 助。
由于 Transact-SQL 游 标 和 API 游 标 使用于服 务 器端,所以被 称为 服 务 器游 标,
也被 称为 后台游 标,而客 户 端游 标 被 称为 前台游 标 。本章中主要 讲 述服 务 器游标 。
3,游 标 使用步 骤应 用程序 对 每一 个 游 标 的操作 过 程可分 为 五 个 步 骤 (如 图 11-1所示):
( 1)用 DECLARE语 句 声 明、定 义 游 标 的 类 型和 属 性。
( 2)用 OPEN 语 句打 开 和 填 充游 标 。
( 3) 执 行 FETCH 语 句,从 一 个 游 标 中 获 取信息(即 从结 果集中提取若干行 数据 库 )。可按需使用 UPDATE,DELETE语 句在游 标当 前位置上 进 行操作。
( 4)用 CLOSE语 句 关闭 游 标 。
( 5)用 DEALLOCATED语 句 释 放游 标 。
2.游 标 分 类声明 (Declare):为执行某操作声明一个游打开 (Open),打开这个一个游标提取 (Fetch),逐行处理游标中的行空否?,直到全部行处理完为止关闭 (Close),关闭这个游标释放 (Deallocate),释放该游标游标的操作过程示意图通常我 们 使用 DECLARE 来声 明一 个 游 标,主要 内 容 为 游 标 名字,数 据 来 源表和列,选 取 条 件 与属 性。游 标 的 声 明有 两种 格式,SQL-92标 准定 义 和
Transact_SQL扩 展定 义 (但仍支持 SQL-92标 准定 义 ),前者只能 说 明 游 标的 属 性,而不能定 义 游 标 的 类 型 。
1,SQL-92标 准定 义
SQL-92标 准 声 明游 标 的 语 法格式如下:
DECLARE 游 标 名 [INSENSITIVE] [SCROLL] CURSOR
FOR select_语 句
[FOR {READ ONLY | UPDATE [OF 列名 1[,… n]]}]
语 法格式中 参数说 明如表 11-1。
例 [11-1】 建立一游 标,用于 访问 pubs数 据 库 中 authors表。
use pubs
DECLARE authors_cursor CURSOR --声 明游 标
FOR SELECT * FROM authors
OPEN authors_cursor
--从 游 标 中提取一 记录 行,由于 为 指定 SCROLL选项,
那 么 FETCH NEXT是唯一的提取 选项 。
11-2 声明游标
FETCH NEXT FROM authors_cursor
Close authors_cursor --关闭 游 标运 行 结 果如下:
-------------------------------------------------------------------------------------------------------- ---------
238-95-7766 Carson Cheryl 415 548-7723 589 Darwin Ln,Berkeley CA 94705 1
表 11-1 SQL-92标 准 语 法 参数说 明例 [11-2】 建立一 个 只 读 游 标 。
declare cur_authors cursor for
select au_lname,au_fname,phone,address,city,state from authors
for read only
Transact_SQL扩 展定 义 游 标语 法格式 为,
DECLARE游 标 名 CURSOR
[LOCAL | GLOBAL]
[FORWARD_ONLY | SCROLL]
[STATIC | KEYSET | DYNAMIC | FAST_FORWARD]
[READ_ONLY | SCROLL_LOCKS | OPTIMISTIC]
[TYPE_WARNING]
FOR select_语 句
[FOR UPDATE [OF column_name [,...n]]]
语 法格式中 参数简 要 说 明如表 11-2。
2,Transact_SQL扩 展定 义参 数 参 数 说 明游 标 名 给 出所定 义 的游 标 名 称,必 须 遵 从标识 符 规则 。
INSENSITIVE
使用 INSENSITIVE 选项,表明 SQL Server 会将 游 标 定 义 所 选 取出来 的 数 据 记录 存放在 tempdb 数 据 库 下的 临时 表 内,对该 游 标 的 读 取操作皆在 这个临时 表里 进 行,因此游 标 不 会随 着基本表 内 容的改 变而改 变,同 时 也无法通 过 游 标来 更新基本表。如果不使用 该 保留字那 么对 基本表的更新 删 除都 会 体 现 到游 标 中。
SCROLL
指定所 选 的提取操作( FIRST,LAST,PRIOR,NEXT、
RELATIVE,ABSOLUTE)均可用,若不 选 用 SCROLL选项,那 么
FETCH NEXT是唯一的提取 选项 。 SCROLL 增加了提取 数 据的 灵活性。
SELECT_语 句用于定 义 游 标 所要 进 行 处 理的 结 果集。在 标 准的 select语 句中游 标 中不能使用 COMPUTE,COMPUTE BY,FOR BROWSE,INTO 语句。
READ ONLY 不允 许 游 标内数 据被更新,是一 种 只 读状态 。 UPDATE,DELETE等语 句不能使用游 标
UPDATE 用于定 义 游 标内 可更新字段列。若指定 of 字段列 [,…n]] 参数,则 所列出的字段列可被更新修改,否 则 所有的列都 将 被更新修改。
使用 Transact_SQL扩 展定 义 游 标时 需注意:
( 1)若在指定 FORWARD_ONLY 时 不指定 STATIC,KEYSET 和 DYNAMIC 关键 字,
则 游 标 作 为 DYNAMIC 游 标进 行操作。若 FORWARD_ONLY 和 SCROLL 均未指定,
除非指定 STATIC,KEYSET 或 DYNAMIC 关键 字,否 则 默 认为 FORWARD_ONLY。
STATIC,KEYSET 和 DYNAMIC 游 标 默 认为 SCROLL。 FAST_FORWARD 和
FORWARD_ONLY 是互斥的;如果指定一 个,则 不能指定另一 个 。
( 2)若指定 FAST_FORWARD,则 不能也指定 SCROLL,FOR_UPDATE、
SCROLL_LOCKS和 FORWARD_ONLY。 FAST_FORWARD 和 FORWARD_ONLY 是互斥的。
3,游 标变 量游 标变 量是一 种 新增 数 据 类 型,用于定 义 一 个 游 标变 量 。 可先 声 明一 个 游 标,如:
declare yu_cur scroll cursor for
select * from titleauthor
再使用 SET 语 句 将 一游 标赋值给 游 标变 量。
declare @pan cursor
set @pan = yu_cur
当 然,可 将声 明游 标语 句放在游 标赋值语 句中。
declare @pan cursor
declare yu_cur scroll cursor for
select * from titleauthor
set @pan = yu_cur
参 数 参 数 说 明
LOCAL
指定 该 游 标为 局部游 标,即其作用域 仅 限在所在的存 储过 程,触发 器或批 处 理中。
当 建立游 标 的存 储过 程或 触发 器等 结 束后,游 标会 被自 动释 放;但可在存 储过 程中使用 OUTPUT 保留字,将 游 标传递给该 存 储过 程的 调 用者,在存 储过 程 结 束后,
还 可引用 该 游 标变 量。
GLOBAL 指定 该 游 标为 全局游 标,即作用域是整 个当 前 连 接。 选项 表明在整 个连 接的任何存储过 程,触发 器或批 处 理中都可以使用 该 游 标,该 游 标 在 连 接 断开时会 自 动隐 性 释放。
FORWAR
D_ONLY
游 标 提取 数 据 时 只能 从 第一行向前 滚动 到最后一行,FETCH NEXT是唯一支持的提取 选项 。
SCROLL
指 定所 选 的 提取 操 作 ( 如 FIRST,LAST,PRIOR,NEXT,RELATIVE、
ABSOLUTE) 均可用,SCROLL 增加了提取 数 据的 灵 活性,可 随 意 读 取 结 果集中的行 数 据而不必重新打 开 游 标 。
STATIC STATIC:定 义 游 标为静态 游 标,与 INSENSITIVE 选项 作用相同 。
KEYSET
指定游 标为键 集 驱动 游 标,即 当 游 标 打 开时,游 标 中 记录 行的 顺 序已 经 固定 。 对记录 行 进 行唯一 标识 的 键 集 内 置在 tempdb 内 一 个称为 keyset 的表中 。 对 基表中的非 键值 所做的更改在用 户滚动 游 标时 是可 视 的 。 其他用 户进 行的 插 入是不可 视 的 。
如果某行已 删 除,则对该 行的提取操作 将 返回 @@FETCH_STATUS 值 -2。
DYNAMI
C
定 义 游 标为动态 游 标 。 即基 础 表的 变 化 将 反映到游 标 中,行的 数 据 值,顺 序和成 员在每次提取 时 都 会 更改 。 使用 该选项 可保 证数 据的一致性,不支持 ABSOLUTE选项 。
游 标 在 声 明以后如果要 从 游 标 中 读 取 数 据,必 须 打 开 游 标 。 打 开 一 个 Transact-SQL服 务 器游 标 使用 OPEN 命令,其 语 法 规则为,
OPEN { { [GLOBAL] 游 标 名 } | cursor_variable_name}
各 参数说 明如下:
GLOBAL:定 义 游 标为 一全局游 标 。
游 标 名:已 声 明的游 标 名 称 。默 认为 局部游 标 。
cursor_variable_name,为 游 标变 量名,该 名 称 引用一 个 游 标 。
打 开 一 个 游 标 被后可用 @@ERROR全局 变 量 来 判 断 成功 与 否,当 @@ERROR为 0,则 表示成功。在游 标 被成功打 开 后,@@CURSOR_ROWS 全局 变 量 将 用 来记录 游 标内数 据行 数,
@@CURSOR_ROWS 的返回 值 有以下四 个 (如表 11-3 所示)。 表 11-3 全局变量
@@CURSOR_ROWS 变量返回值说明。
11-3 打 开 游 标返回 值 返 回 值 说 明 zzzzzzzzzz
-m 表示 从 基 础 表向游 标读 入 数 据的 处 理仍在 进 行,(-m) 表示 当 前在游 标 中的 数 据行数 。
-1 表示 该 游 标 是 动态 的。由于 动态 游 标 可反映基 础 表的所有 变 化,因此符合游 标 定义 的 数 据行 经 常 变动,故无法确定。
0 表示无符合 条 件的 记录 或游 标 已被 关闭
n 表示 从 基 础 表 读 入 数 据已 经结 束 n 即 为 游 标 中已有 数 据 记录 的行 数 据当 游 标 被 声 明和成功打 开 后,就可以 从 游 标 中逐行地提( 读 )取 数 据,以供相 关处 理。
从 游 标 中提取 数 据的 语 法格式如下:
FETCH
[[ NEXT|PRIOR|FIRST|LAST|ABSOLUTE{n|@nvar}|RELATIVE
{n|@nvar} ]
FROM ]
{{[GLOBAL]游 标 名 }|@cursor_variable_name}
[INTO @variable_name[,...n] ]
各 参数 含 义说 明如下:
NEXT,返回 结 果集中 当 前行的下一行,并递 增 当 前 记录 行 数为 返回行行 数 。如果
FETCH NEXT是第一次 读 取游 标数 据,则 返回 结 果集中的首 记录 。 NEXT为 默 认项 。
PRIOR,返回 结 果集中 当 前行的前一行,并递减当 前行 数为 返回行行 数 。如果
FETCH PRIOR是第一次提取游 标 中 数 据,则 无 记录 返回 并 把游 标 置于首 记录 之前。
T返回游 标 中的首 记录并设为当 前 记录 。
1LAST返回游 标 中的末 记录并设为当 前 记录 。
ABSOLUTE{n|@nvar}:若 n 或 @nvar 为 正,则 表示 从 游 标 中返回的 数 据行 数 ;
若 n 或 @nvar 为负,则 返回游 标内从 末 记录数 据算起的第 n 或 @nvar 行 数 据,并设为当 前 记录 。若 n 或 @nvar 超 过 游 标 的 数 据子集范 畴则 @@FETCH_STARS 返回 -
1。若 n 或 @nvar 为负数,则执 行 FETCH NEXT 命令 会 得到第一行 数 据;反之 为 正值,则会 得到最后一行 数 据。
11-4 提取游 标数 据
RELATIVE{n|@nvar},若 n 或 @nvar 为 正 则读 取游 标当 前位置起向后的第
@nvar或 n行 数 据,如果 n 或 @nvar 为负则读 取游 标当 前位置起向前的第 n 或
@nvar 行 数 据。若 n 或 @nvar 超 过 游 标 的 数 据子集范 畴则
@@FETCH_STARS 返回 -1。此 时 若 n 或 @nvar 为负数,则执 行 FETCH
NEXT 语 句 会 得到第一行 数 据;反之 为 正 值,则会 得到最后一行 数 据。
INTO @variable_name[,...n],允 许将 使用 FETCH 语 句 读 取的 数 据存放在若干 个 局部 变 量中,在 变 量行中的每 个变 量必 须与 游 标结 果集中相 应 的列相 对应,每一 变 量的 数 据 类 型也要 与 游 标 中 数 据列的 数 据 类 型相匹配。
图 11-2 打 开,提取 数 据操作 过 程的游 标 指 针 位置执 行 FETCH语 句后,可通 过 @@FETCH_STATUS 全局 变 量返回游 标当 前的 状态 。在每次用 FETCH从 游 标 中 读 取 数 据 时 都 应检查该变 量,以确定上次
FETCH 操作是否成功,进 而可 决 定如何 进 行下一步 处 理。
@@FETCH_STATUS 变 量有三 个 不同的返回 值,
0,FETCH 语 句 执 行成功。
-1,FETCH 语 句 执 行失 败 或者行 数 据超出游 标数 据 结 果集的范 围 。
-2:表示提取的 数 据不存在。
图 11-2 打 开,提取 数 据操作 过 程的游 标 指 针 位置打 开,提取 数 据操作 过 程的游 标 指 针 位置如 图 11-2所示。
在通 过 一 个 游 标 完成提取或更新 记录 行等 处 理 数 据操作后,必 须关闭 游 标来释 放 当 前 数 据 结 果集,并 解除定位于 数 据 记录 上行的游 标锁 定。
CLOSE 语 句可用于 关闭 游 标,但不能 释 放游 标 占用的 数 据 结构,可以使用 DEALLOCATE实现释 放游 标 (即可 删 除游 标与 游 标 名或游 标变 量之 间的 联 系,释 放游 标 占用的所有系 统资 源)。
关闭 游 标 的 语 法格式 为,
CLOSE { { [GLOBAL] 游 标 名 } | cursor_variable_name }
释 放游 标 的 语 法格式 为,
DEALLOCATE { { [GLOBAL] 游 标 名 } | @cursor_variable_name}
各 参数说 明如下:
GLOBAL,说 明游 标为 一全局游 标 。
游 标 名,关闭 或 释 放的游 标 名 称 。默 认为 局部游 标 。
ursor_variable_name,为 游 标变 量名,该 名 称 引用一 个 游 标 。
注,使用事 务结构时,当结 束事 务时 游 标 也 会 自 动关闭 。
11-5 关闭释 放游 标图 11-3 DEALLOCATE语 句和游 标赋值 的使用
【 例 11-3】 建立一,学 生 _cursor”游 标,用于循 环 提取,信息管理,数 据库 中,学 生,表 数 据,运 行 结 果如 图 11-3所示。
use 信息管理
go
declare 学 生 _cursor cursor for --声 明游 标
select 学号,姓名,校名 from 学 生 --打 开 游 标
open 学 生 _cursor --提取游 标数 据
fetch next from 学 生 _cursor --循 环 提取游 标数 据
while @@FETCH_STATUS=0 --检测 @@FETCH_STATUS,
若仍有 记录 行,则继续 循 环
begin
fetch next from 学 生 _cursor
end
close 学 生 _cursor --关闭 游 标
deallocate 学 生 _cursor --释 放游 标
11-6 游 标 的 应 用在前面几 节 我 们 介 绍 了如何 声 明游 标,打 开 游 标,从 游 标 中 读 取 数 据以及 关闭释 放游 标 的方法,下面我 们将 通 过 枚 举两个应 用 实 例使 读 者更深刻地理解游 标 的原理 与应 用。
针对 DEALLOCATE语 句和游 标赋值,下面 给 出一 个 具体的例子 来 加深理解。
use pubs
go /*声 明 并 打 开 一 个 全局游 标 在批 处 理以外 该 游 标 仍然可 见 */
declare titleauthor_cur cursor global scroll for
select * from titleauthor
open titleauthor_cur
go /*用游 标变量引用已 声 明 过 的游 标 */
declare @cur_ta1 cursor
set @cur_ta1 = titleauthor_cur /*现 在 释 放 对 游 标 的引用 */
deallocate @cur_ta1 /*游 标
titleauthor_cur 仍 旧 存在 */
fetch next from titleauthor_cur
go /*再引用游标 */
declare @cur_ta2 cursor
set @cur_ta2 = titleauthor_cur /*释 放 titleauthor_cur 游 标 */
deallocate titleauthor_cur /*由于游 标 被 @cur_ta2 引用所以仍 旧 存在 */
fetch next from @cur_ta2 /*当 最后一 个 游 标变 量超出游 标 作用域时 游 标将 被 释 放 */
go
declare @cur_ta cursor
set @cur_ta = cursor local scroll for
select * from titles /*由于 没 有其 它变 量 对 其 进 行引用所以游 标 被 释放 */
deallocate @cur_ta
go
【 例 11-4】
使用游 标语 句修改,信息管理,数 据 库 下,学 生,中 学号 ='040218'
记录 的 学 分 数值,执 行 结 果如 图 11-4所示。
use 信息管理
go
declare @xh nvarchar(6),@xm nvarchar(8),@fs decimal
declare 学 分游 标 cursor for
select 学号,姓名,学 分 from 学 生 where 学号 ='040218'
open 学 分游 标 --提取游 标数 据
fetch NEXT from 学 分游 标 into @xh,@xm,@fs
print '修改前,'+@xh+@xm+'同 学学 分 为,'+convert(varchar,@fs)
update 学 生 set 学 分 =学 分 +10
where current of 学 分游 标
close 学 分游 标
open 学 分游 标
fetch NEXT from 学 分游 标 into @xh,@xm,@fs
print '修改后,'+@xh+@xm+'同 学学 分 为,'+convert(varchar,@fs)
close 学 分游 标 --关闭 游 标
deallocate 学 分游 标
go --释 放游 标
【 例 11-5】
游 标 是一 个值 得人 们关 注的 概 念,是一 种处 理 数 据的方法,游 标总 是 与 一条 Transact-SQL选择语 句相 关联 。 它 可 对结 果集 进 行逐行 处 理,可 将 游 标视 作一 种 指 针,用于指向 并处 理 结 果集任意位置的 数 据。 应 用程序 对 每一 个 游 标 的操作 过 程可分 为 用 DECLARE语 句 声 明、定 义 游 标 的 类 型和 属 性、用 Open语 句打开 和 填 充游 标,执 行 Fetch语 句、用 Close语 句 关闭 游 标,用 Dealloocated语 句释 放游 标 五 个 步 骤 。
本章 还 介 绍 了如何 声 明游 标,打 开 游 标,从 游 标 中 读 取 数 据以及 关闭释 放游 标 的方法,并 通 过 枚 举应 用 实 例使 读 者更深刻地理解游 标 的原理 与应 用。
习题 十一
1,何 谓 游 标? 简 述其特点 。
2,简 述 SQL Server 2000下游 标 的分 类 。
3,简 述游 标 的操作步 骤 。
4,简 述游 标声 明的 两种 格式 。
5,简 述在 SQL Server 2000中打 开 游 标 的方法 。
6,简 述在 SQL Server 2000的游 标 中逐行提 ( 读 ) 取 数 据的方法 。
7,简 述 关闭 游 标 的 语 法格式 。
8,简 述 释 放游 标 的 语 法格式 。
11-7 本章小 结