2009-04-19 22:40 SQL SERVER游标的讲解
游标和游标的优点
在数据库中,游标是一个十分重要的概念。游标提供了一种对从表中检索出的数据进行操作的灵活手段,就本质而言,游标实际上是一种能从包括多条数据记录的结
果集中每次提取一条记录的机制。游标总是与一条T_SQL
选择语句相关联因为游标由结果集(可以是零条、一条或由相关的选择语句检索出的多条记录)和结果集中指向特定记录的游标位置组成。当决定对结果集进行处理
时,必须声明一个指向该结果集的游标。如果曾经用 C
语言写过对文件进行处理的程序,那么游标就像您打开文件所得到的文件句柄一样,只要文件打开成功,该文件句柄就可代表该文件。对于游标而言,其道理是相同
的。可见游标能够实现按与传统程序读取平面文件类似的方式处理来自基础表的结果集,从而把表中数据以平面文件的形式呈现给程序。
我们知道关系数据库管理系统实质是面向集合的,在MS SQL SERVER 中并没有一种描述表中单一记录的表达形式,除非使用where 子句来限制只有一条记录被选中。因此我们必须借助于游标来进行面向单条记录的数据处理。
由此可见,游标允许应用程序对查询语句select
返回的行结果集中每一行进行相同或不同的操作,而不是一次对整个结果集进行同一种操作;它还提供对基于游标位置而对表中数据进行删除或更新的能力;而且,
正是游标把作为面向集合的数据库管理系统和面向行的程序设计两者联系起来,使两个数据处理方式能够进行沟通。
游标种类
MS SQL SERVER 支持三种类型的游标:Transact_SQL 游标,API 服务器游标和客户游标。
(1) Transact_SQL 游标
Transact_SQL 游标是由DECLARE CURSOR 语法定义、主要用在Transact_SQL
脚本、存储过程和触发器中。Transact_SQL 游标主要用在服务器上,由从客户端发送给服务器的Transact_SQL
语句或是批处理、存储过程、触发器中的Transact_SQL 进行管理。 Transact_SQL 游标不支持提取数据块或多行数据。
(2) API 游标
API 游标支持在OLE DB, ODBC 以及DB_library 中使用游标函数,主要用在服务器上。每一次客户端应用程序调用API
游标函数,MS SQL SEVER 的OLE DB 提供者、ODBC驱动器或DB_library 的动态链接库(DLL)
都会将这些客户请求传送给服务器以对API游标进行处理。
(3) 客户游标
客户游标主要是当在客户机上缓存结果集时才使用。在客户游标中,有一个缺省的结果集被用来在客户机上缓存整个结果集。客户游标仅支持静态游标而非动态游
标。由于服务器游标并不支持所有的Transact-SQL
语句或批处理,所以客户游标常常仅被用作服务器游标的辅助。因为在一般情况下,服务器游标能支持绝大多数的游标操作。
由于API 游标和Transact-SQL 游标使用在服务器端,所以被称为服务器游标,也被称为后台游标,而客户端游标被称为前台游标。在本章中我们主要讲述服务器(后台)游标。
每一个游标必须有四个组成部分这四个关键部分必须符合下面的顺序;
1.DECLARE 游标
2.OPEN 游标
3.从一个游标中FETCH 信息
4.CLOSE 或DEALLOCATE 游标
通常我们使用DECLARE 来声明一个游标声明一个游标主要包括以下主要内容:
游标名字
数据来源(表和列)
选取条件
属性(仅读或可修改)
其语法格式如下:
DECLARE cursor_name [INSENSITIVE] [SCROLL] CURSOR
FOR select_statement
[FOR {READ ONLY | UPDATE [OF column_name [,...n]]}]
其中:
cursor_name
指游标的名字。
INSENSITIVE
表明MS SQL SERVER 会将游标定义所选取出来的数据记录存放在一临时表内(建立在tempdb 数据库下)。对该游标的读取操作皆由临时表来应答。因此,对基本表的修改并不影响游标提取的数据,即游标不会随着基本表内容的改变而改变,同时也无法通过
游标来更新基本表。如果不使用该保留字,那么对基本表的更新、删除都会反映到游标中。
另外应该指出,当遇到以下情况发生时,游标将自动设定INSENSITIVE 选项。
在SELECT 语句中使用DISTINCT、 GROUP BY、 HAVING UNION 语句;
使用OUTER JOIN;
所选取的任意表没有索引;
将实数值当作选取的列。
SCROLL
表
明所有的提取操作(如FIRST、 LAST、 PRIOR、 NEXT、 RELATIVE、
ABSOLUTE)都可用。如果不使用该保留字,那么只能进行NEXT 提取操作。由此可见,SCROLL
极大地增加了提取数据的灵活性,可以随意读取结果集中的任一行数据记录,而不必关闭再
重开游标。
select_statement
是定义结果集的SELECT 语句。应该注意的是,在游标中不能使用COMPUTE、COMPU- TE BY、 FOR BROWSE、 INTO 语句。
READ ONLY
表明不允许游标内的数据被更新尽管在缺省状态下游标是允许更新的。而且在UPDATE或DELETE 语句的WHERE CURRENT OF 子句中,不允许对该游标进行引用。
UPDATE [OF column_name[,…n]]
定义在游标中可被修改的列,如果不指出要更新的列,那么所有的列都将被更新。当游标被成功创建后,游标名成为该游标的惟一标识,如果在以后的存储过程、触发器或Transact_SQL 脚本中使用游标,必须指定该游标的名字。
上面介绍的是SQL_92 的游标语法规则。下面介绍MS SQL SERVER 提供的扩展了的游标声明语法,通过增加另外的保留字,使游标的功能进一步得到了增强其语法规则为;
LOCAL
定
义游标的作用域仅限在其所在的存储过程、触发器或批处理中。当建立游标的存储过程执行结束后,游标会被自动释放。因此,我们常在存储过程中使用
OUTPUT
保留字,将游标传递给该存储过程的调用者,这样在存储过程执行结束后,可以引用该游标变量,在该种情况下,直到引用该游标的最后一个就是被释放时,游标才
会自动释放。
GLOBAL
定义游标的作用域是整个会话层会话层指用户的连接时间它包括从用户登录到SQLSERVER 到脱离数据库的整段时间。选择GLOBAL 表明在整个会话层的任何存储过程、触发器或批处理中都可以使用该游标,只有当用户脱离数据库、时该游标才会被自动释放。
注意:如果既未使用GLOBAL也未使用LOCAL,那么SQL SERVER将使用default local cursor数据库选项,为了与以彰的版本歉容,该选项常设置为FALSE。
FORWARD_ONLY
选
项指明在从游标中提取数据记录时,只能按照从第一行到最后一行的顺序,此时只能选用FETCH NEXT 操作。除非使用STATIC, KEYSET
和DYNAMIC 关键字,否则如果未指明是使用FORWARD_ONLY 还是使用SCROLL, 那么FORWARD_ONLY
将成为缺省选项,因为若使用STATIC KEYSET 和DYNAMIC 关键字,则变成了SCROLL
游标。另外如果使用了FORWARD_ONLY, 便不能使用FAST_FORWARD。
STATIC
选项的含义与
INSENSITIVE 选项一样,MS SQL SERVER 会将游标定义所选取出来的数据记录存放在一临时表内(建立在tempdb
数据库下)。对该游标的读取操作皆由临时表来应答。因此对基本表的修改并不影响游标中的数据,即游标不会随着基本表内容的
改变而改变,同时也无法通过游标来更新基本表。
KEYSET
指
出当游标被打开时,游标中列的顺序是固定的,并且MS SQL SERVER 会在tempdb内建立一个表,该表即为KEYSET KEYSET
的键值可惟一识别游标中的某行数据。当游标拥有者或其它用户对基本表中的非键值数据进行修改时,这种变化能够反映到游标中,所以游标用户或所有者可以通过
滚动游标提限这些数据。
当其它用户增加一条新的符合所定义的游标范围的数据时,无法由此游标读到该数据。因为Transact-SQL 服务器游标不支持INSERT 语句。
如果在游标中的某一行被删除掉,那么当通过游标来提取该删除行时,@@FETCH_STATUS 的返回值为-2。 @@FETCH_STATUS 是用来判断读取游标是否成功的系统全局变量。
由于更新操作包括两部分:删除原数据插入新数据,所以如果读取原数据,@@FETCH_STATUS 的返回值为-2; 而且无法通过游标来读取新插入的数据。但是如果使用了WHERE CURRENT OF 子句时,该新插入行数据便是可见的。
注意:如果基础表未包含惟一的索引或主键,则一个KEYSET游标将回复成STATIC游标。
DYNAMIC
指明基础表的变化将反映到游标中,使用这个选项会最大程度上保证数据的一致性。然而,与KEYSET 和STATIC 类型游标相比较,此类型游标需要大量的游标资源。
FAST_FORWARD
指明一个FORWARD_ONLY, READ_ONLY 型游标。此选项已为执行进行了优化。如果SCROLL 或FOR_UPDATE 选项被定义,则FAST_FORWARD 选项不能被定义。
SCROLL_LOCKS
指
明锁被放置在游标结果集所使用的数据上当。数据被读入游标中时,就会出现锁。这个选项确保对一个游标进行的更新和删除操作总能被成功执行。如果
FAST_FORWARD选项被定义,则不能选择该选项。另外,由于数据被游标锁定,所以当考虑到数据并发处理时,应避免使用该选项。
OPTIMISTIC
指明在数据被读入游标后,如果游标中某行数据已发生变化,那么对游标数据进行更新或删除可能会导致失败。如果使用了FAST_FORWARD 选项,则不能使用该选项。
TYPE_WARNING
指明若游标类型被修改成与用户定义的类型不同时,将发送一个警告信息给客户端。
注意:不可以将SQL_92的游标语法规则与MS SQL SERVER的游标扩展用法混合在一起使用。
下面我们将总结一下声明游标时应注意的一些问题。
如果在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 语句的用户而言,它也具有使用游标的缺省权限。
打开游标游标在声明以后,如果要从游标中读取数据必须打开游标。打开一个Transact-SQL服务器游标使用OPEN 命令,其语法规则为:
OPEN { { [GLOBAL] cursor_name } | cursor_variable_name}
各参数说明如下:
GLOBAL
定义游标为一全局游标。
cursor_name
为声明的游标名字。如果一个全局游标和一个局部游标都使用同一个游标名,则如果使用GLOBAL 便表明其为全局游标,否则表明其为局部游标。
cursor_variable_name
为游标变量。当打开一个游标后时,MS SQL SERVER 首先检查声明游标的语法是否正确,如果游标声明中有变量,则将变量值带入。
在打开游标时,如果游标声明语句中使用了INSENSITIVE 或STATIC
保留字,则OPEN产生一个临时表来存放结果集;如果在结果集中任何一行数据的大小超过MS SQL SERVER定义的最大行尺寸时,OPEN
命令将失败;如果声明游标时作用了KEYSET 选项,则OPEN 产生一个临时表来存放键值。所有的临时表都存在tempdb 数据库中。
在游标被成功打开之后,@@CURSOR_ROWS 全局变量将用来记录游标内数据行数。为了提高性能,MS SQL SERVER
允许以异步方式从基础表向KEYSET 或静态游标读入数据,即如果MS SQL SERVER
的查询优化器估计从基础表中返回给游标的数据行已经超过sp_configure cursor threshold 参数值,则MS SQL
SERVER
将启动另外一个独立的线程来继续从基础表中读入符合游标定义的数据行,此时可以从游标。中读取数据进行处理而不必等到所有的符合游标定义的数据行都从基础
表中读入游标 @@CURSOR_ROWS 变量存储的正是在调用@@CURSOR_ROWS
时,游标已从基础表读入的数据行。@@CURSOR_ROWS 的返回值有以下四个,如表13-1 所示。
如果所打开的游标在声明时带有SCROLL 或INSENSITIVE 保留字,那么@@CURSOR_ROWS
的值为正数且为该游标的所有数据行。如果未加上这两个保留字中的一个,则@@CURSOR_ROWS 的值为-1, 说明该游标内只有一条数据记录。
当游标被成功打开以后,就可以从游标中逐行地读取数据,以进行相关处理。从游标中读取数据主要使用FETCH 命令。其语法规则为:
各参数含义说明如下:
?NEXT
返回结果集中当前行的下一行,并增加当前行数为返回行行数。如果FETCH NEXT是第一次读取游标中数据,则返回结果集中的是第一行而不是第二行。
RIOR
返回结果集中当前行的前一行,并减少当前行数为返回行行数。如果FETCH PRIOR是第一次读取游标中数据,则无数据记录返回,并把游标位置设为第一行。
FIRST
返回游标中第一行。
LAST
返回游标中的最后一行。
ABSOLUTE {n | @nvar}
如
果n 或@nvar 为正数,则表示从游标中返回的数据行数。如果n 或@nvar 为负数,则返回游标内从最后一行数据算起的第n 或@nvar
行数据。若n 或@nvar 超过游标的数据子集范畴,则@@FETCH_STARS 返回-1, 在该情况下,如果n 或@nvar
为负数,则执行FETCH NEXT 命令会得到第一行数据,如果n 或@nvar为正值,执行FETCH PRIOR 命令则会得到最后一行数据。n
或@nvar 可以是一固定值也可以是一smallint, tinyint 或int 类型的变量。
RELATIVE {n | @nvar}
若
n 或@nvar 为正数,则读取游标当前位置起向后的第n 或@nvar 行数据;如果n 或@nvar 为负数,则读取游标当前位置起向前的第n
或@nvar 行数据。若n 或@nvar 超过游标的数据子集范畴,则@@FETCH_STARS 返回-1, 在该情况下,如果n 或@nvar
为负数,则执行FETCH NEXT 命令则会得到第一行数据;如果n 或@nvar 为正值,执行FETCH PRIOR
命令则会得到最后一行数据。n 或@nvar 可以是一固定值也可以是一smallint, tinyint或int 类型的变量。
INTO @variable_name[,...n]
允许将使用FETCH 命令读取的数据存放在多个变量中。在变量行中的每个变量必须与游标结果集中相应的列相对应,每一变量的数据类型也要与游标中数据列的数据类型相匹配。
@@FETCH_STATUS 全局变量返回上次执行FETCH
命令的状态。在每次用FETCH从游标中读取数据时,都应检查该变量,以确定上次FETCH
操作是否成功,来决定如何进行下一步处理。@@FETCH_STATUS 变量有三个不同的返回值,如表13-2。
在使用FETCH 命令从游标中读取数据时,应该注意以下的情况:
当使用SQL-92 语法来声明一个游标时,没有选择SCROLL 选项时,只能使用FETCH NEXT
命令来从游标中读取数据,即只能从结果集第一行按顺序地每次读取一行,由于不能使用FIRST、 LAST、 PRIOR,
所以无法回滚读取以前的数据。如果选择了SCROLL 选项,则可能使用所有的FETCH 操作。
当使用MS SQL SERVER 的扩展语法时,必须注意以下约定:
如果定义了FORWARD-ONLY 或FAST_FORWARD 选项,则只能使用FETCH NEXT命令;
如果没有定义DYNAMIC, FORWARD_ONLY 或FAST_FORWARD 选项,而定义了KEYSET, STATIC 或SCROLL 中的任何一个,则可使用所有的FETCH 操作;
DYNAMIC SCROLL 游标支持所有的FETCH, 选项但禁用ABSOLUTE 选项。
关闭游标
1、使用CLOSE 命令关闭游标
在处理完游标中数据之后必须关闭游标来释放数据结果集和定位于数据记录上的锁。CLOSE 语句关闭游标,但不释放游标占用的数据结构。如果准备在随后的使用中再次打开游标,则应使用CLOSE 命令。其关闭游标的语法规则为:
CLOSE { { [GLOBAL] cursor_name } | cursor_variable_name }
2、自动关闭游标
我们已经了解到游标可应用在存储过程、触发器和Transact_SQL 脚本中。如果在声明游标与释放游标之间使用了事务结构,则在结束事务时游标会自动关闭。其具体的情况如下所示:
(1)、声明一个游标
(2)、打开游标
(3)、读取游标
(4)、BEGIN TRANSATION
(5)、数据处理
(6)、COMMIT TRANSATION
(7)、回到步骤3
在这样的应用环境中。当从游标中读取一条数据记录进行以BEGIN TRANSATION为开头,COMMIT TRANSATION
或ROLLBACK 为结束的事务处理时,在程序开始运行后,第一行数据能够被正确返回,经由步骤7, 程序回到步骤3,
读取游标的下一行,此时常会发现游标未打开的错误信息。其原因就在于当一个事务结束时,不管其是以COMMIT TRANSATION
还是以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}
各参数的含义参看13.3 打开游标一节。
当使用DEALLOCATE @cursor_variable_name 来删除游标时,游标变量并不会被释放,除非超过使用该游标的存储过程、触发器的范围(即游标的作用域)。
在这一步中,需要指定游标的属性和根据要求产生的结果集。有两种方法可以指定一个游标。
形式1(ANSI 92)
DECLARE cursor_name [INSENSITIVE] [SCROLL] CURSOR
FOR select_statement
[FOR {READ ONLY | UPDATE ][OF column_list]}]
形式2
DECLARE cursor_name CURSOR
[LOCAL | GLOBAL]
[FORWARD_ONLY | SCROLL]
[STATIC | KEYSET | DYNAMIC]
[READ_ONLY | SCROLL_LOCKS | OPTIMISTIC]
FOR select_statement
[FOR {READ ONLY | UPDATE ][OF column_list]}]
INSENSITIVE关键字指明要为检索到的结果集建立一个临时拷贝,以后的数据从这个临时拷贝中获取。如果在后来游标处理的过程中,原有基表中数据发生了改变,那么它们对于该游标而言是不可见的。这种不敏感的游标不允许数据更改。
SCROLL关键字指明游标可以在任意方向上滚动。所有的fetch选项(first、last、next、relative、absolute)都可以在游标中使用。如果忽略该选项,则游标只能向前滚动(next)。
Select_statement指明SQL语句建立的结果集。Transact SQL语句COMPUTE、COMPUTE BY、FOR BROWSE和INTO在游标声明的选择语句中不允许使用。
READ ONLY指明在游标结果集中不允许进行数据修改。
UPDATE关键字指明游标的结果集可以修改。
OF column_list指明结果集中可以进行修改的列。缺省情况下(使用UPDATE关键字),所有的列都可进行修改。
LOCAL关键字指明游标是局部的,它只能在它所声明的过程中使用。
GLOBAL关键字使得游标对于整个连接全局可见。全局的游标在连接激活的任何时候都是可用的。只有当连接结束时,游标才不再可用。
FORWARD_ONLY指明游标只能向前滚动。
STATIC的游标与INSENSITIVE的游标是相同的。
KEYSET指明选取的行的顺序。SQL Server将从结果集中创建一个临时关键字集。如果对数据库的非关键字列进行了修改,则它们对游标是可见的。因为是固定的关键字集合,所以对关键字列进行修改或新插入列是不可见的。
DYNAMIC指明游标将反映所有对结果集的修改。
SCROLL_LOCK是为了保证游标操作的成功,而对修改或删除加锁。
OPTIMISTIC指明哪些通过游标进行的修改或者删除将不会成功。
注意:
· 如果在SELECT语句中使用了DISTINCT、UNION、GROUP BY语句,且在选择中包含了聚合表达式,则游标自动为INSENSITIVE的游标。
· 如果基表没有唯一的索引,则游标创建成INSENSITIVE的游标。
· 如果SELECT语句包含了ORDER BY,而被ORDER BY的列并非唯一的行标识,则DYNAMIC游标将转换成KEYSET游标。如果KEYSET游标不能打开,则将转换成INSENSITIVE游标。使用 SQL ANSI-92语法定义的游标同样如此,只是没有INSENSITIVE关键字而已。
ii. 打开游标
打开游标就是创建结果集。游标通过DECLARE语句定义,但其实际的执行是通过OPEN语句。语法如下:
OPEN { { [GLOBAL] cursor_name } | cursor_variable_name}
GLOBAL指明一个全局游标。
Cursor_name是被打开的游标的名称。
Cursor_variable_name是所引用游标的变量名。该变量应该为游标类型。
在游标被打开之后,系统变量@@cursor_rows可以用来检测结果集的行数。@@cursor_rows为负数时,表示游标正在被异步迁移,其绝 对值(如果@@cursor_rows为-5,则绝对值为5)为当前结果集的行数。异步游标使用户在游标被完全迁移时仍然能够访问游标的结果。
iii. 从游标中取值
在 从游标中取值的过程中,可以在结果集中的每一行上来回移动和处理。如果游标定义成了可滚动的(在声明时使用SCROLL关键字),则任何时候都可取出结果 集中的任意行。对于非滚动的游标,只能对当前行的下一行实施取操作。结果集可以取到局部变量中。Fetch命令的语法如下:
FETCH [NEXT | PRIOR| FIRST | LAST | ABSOLUTE {n | @nvar} | RELATIVE {n | @nvar}]
FROM [GLOBAL] cursor_name} | cursor_variable_name}
[INTO @variable_name ][,……n]]
NEXT指明从当前行的下一行取值。
PRIOR指明从当前行的前一行取值。
FIRST是结果集的第一行。
LAST是结果集的最后一行。
ABSOLUTE n表示结果集中的第n行,该行数同样可以通过一个局部变量传播。行号从0开始,所以n为0时不能得到任何行。
RELATIVE n表示要取出的行在当前行的前n行或后n行的位置上。如果该值为正数,则要取出的行在当前行前n行的位置上,如果该值为负数,则返回当前行的后n行。
INTO @cursor_variable_name表示游标列值存储的地方的变量列表。该列表中的变量数应该与DECLARE语句中选择语句所使用的变量数相 同。变量的数据类型也应该与被选择列的数据类型相同。直到下一次使用FETCH语句之前,变量中的值都会一直保持。
每一次FETCH的 执行都存储在系统变量@@fetch_status中。如果FETCH成功,则@@fetch_status被设置成0。@@fetch_status为 -1表示已经到达了结果集的一部分(例如,在游标被打开之后,基表中的行被删除)。@@fetch_status可以用来构造游标处理的循环。
例如:
DECLARE @iname char(20), @fname char(20)
OPEN author_cur
FETCH FIRST FROM author_cur INTO @iname, @fname
WHILE @@fetch_status = 0
BEGIN
IF @fname = ‘Albert’
PRINT “Found Albert Ringer”
ELSE
Print “Other Ringer”
FETCH NEXT FROM author_cur INTO @iname, @fname
END
iv. 关闭游标
CLOSE语句用来关闭游标并释放结果集。游标关闭之后,不能再执行FETCH操作。如果还需要使用FETCH语句,则要重新打开游标。语法如下:
CLOSE [GLOBAL] cursor_name | cursor_variable_name
v. 释放游标
游标使用不再需要之后,要释放游标。DEALLOCATE语句释放数据结构和游标所加的锁。语法如下:
DEALLOCATE [GLOBAL] cursor_name | cursor_variable_name
下面给出游标的一个完整的例子:
USE master
GO
CREATE PROCEDURE sp_BuildIndexes
AS
DECLARE @TableName sysname, @msg varchar(100), @cmd varchar(100)
DECLARE table_cur CURSOR FOR
SELECT name FROM sysobjects WHERE type=’u’
OPEN table_cur
FETCH NEXT FROM table_cur INTO @TableName
WHILE @@fetch_status = 0
BEGIN
IF @@fetch_status = -2
CONTINUE
SELECT @msg = “Building indexes for +”…”
PRINT @msg
SELECT @cmd = “DBCC DBREINDEX ()”
EXEC (@cmd)
PRINT “ “
FETCH NEXT FROM table_cur INTO @TableName
END
DEALLOCATE table_cur
GO
下面的脚本将为PUBS数据库执行sp_BuildIndexes
USE pubs
GO
EXEC ap_BuildIndexes
注意:上面也是创建用户定义的系统存储过程的示例。
使用临时表
临时表是在TempDB中创建的表。临时表的名称都以“#”开头。临时表的范围为创建临时表的连接。因为,临时表不能在两个连接之间共享,一旦连接关 闭,临时表就会被丢弃。如果临时表被创建于存储过程之中,则临时表的范围在存储过程之中,或者被该存储过程调用的任何存储过程之中。如果需要在连接之间共 享临时表,则需要使用全局的临时表。全局的临时表以“##”符号开头,它将一直存在于数据库中,直到SQL Server重新启动。一旦这类临时表创建之后,所有的用户都可以访问到。在临时表上不能明确地指明权限。 临时表提供了存储中间结果的能力。有时候,临时表还能通过将一个复杂的查询分解成两个查询而获得性能的改善。这可以通过首先将第一个查询的结果存在临时表 中,然后在第二个查询中使用临时表来实现。当一个大表中的某个子集在一个在座过程中使用多次时,建议使用临时表。在这种情况下,在临时表中保持数据的子 集,以在随后的连接中使用,这样能大大改善性能。还可以在临时表中创建索引。