以前作东西的时候遇到须要用有标的, 当时就仿照着别人的例子写的, 最近忽然想起来, 就想系统的看一下游标。html
原文连接数据库
定义概念性能优化
游标是处理数据的一种方法,为了查看或者处理结果集中的数据, 游标提供了在结果集中一次一行或者多行前进或者向后浏览数据的能力。能够吧游标看成一个指针,他能够指定结果中的任何位置,而后容许用户对指定位置的数据进行处理。服务器
使用规范及示例性能
1.声明游标fetch
游标主要包含游标结果集合游标位置两个部分,游标结果集是定义游标的select语句返回的行集合,游标的位置则是指向这个结果集中的某一行指针。优化
使用游标以前, 必需要先声明游标, SQL Server中声明使用declare cursor 语句,声明游标包含定义游标的滚动行为和用户生成游标所操做的结果集的查询:ui
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] ] ]
说明:spa
cursor_name:是所定义的T_SQL 服务器游标的名称。指针
LOCAL:对于在其中建立批处理、存储过程或触发器来讲,该游标的做用域是局部的。
GLOBAL:指定该游标的做用域是全局的
FORWARD_ONLY:指定游标只能从第一行滚动到最后一行。FETCH NEXT是惟一支持的提取选项,若是在指定FORWARD_ONLY时不指定STATIC,KEYSET和DYNAMIC关键字,则游标做为DYNAMIC游标进行操做,若是FORWARD_ONLY和SCROLL均为指定,则除非指定STATIC,KEYSET和DYNAMIC关键字,不然默认为FORWARD_ONLY。STATIC,KEYSET和DYNAMIC游标默认为SCROLL。与ODBC和ADO这类数据库API不一样,STATIC,KEYSET和DYNAMIC T_SQL游标支持FORWARD_ONLY。
STATIC:定义一个游标,以建立将又该游标使用的数据临时复本,对游标的全部请求都从tempdb中的这以临时表中不获得应答;所以,在对该游标进行提取操做时返回的数据中不反映对基表所作的修改,而且该游标不容许修改。
KEYSET:指定当游标打开时,游标重的行的成员身份和顺序已经固定。对行进行惟一标识的键值内置在tempdb内一个称为keyset的表中。
DYNAMIC:定义一个游标,以反映在滚动游标时对结果集内的各行所作的全部数据更改。行的数据值、顺序和成员身份在每次提取时都会更改,动态游标不支持ABSOLUTE提取选项。
FAST_FORWARD:指定启动了性能优化的FORWARD_ONLY、READ_ONLY游标。若是指定了SCROLL或FOR_UPDATE,则不能指定FAST_FORWARD。
SCROLL_LOCKS:指定经过游标进行的定位更新或删除必定会成功。将行读入游标时SQL Server将锁定这些行,以确保随后可对它们进行修改,若是还指定了FAST_FORWARD或STATIC,则不能指定SCROLL_LOCKS。
OPTIMISTIC:指定若是行自读入游标以来已获得更新,则经过游标进行的定位更新或定位删除不成功。当将行读入游标时,SQL Server不锁定行,它改用timestamp列值比较结果来肯定行读入游标后是否发生了修改,若是表不包含timestamp列,它改用校验和值进行肯定,若是以修改该行,则尝试进行的定位更新或删除将失败,若是还指定了FAST_FORWARD,则不能指定OPTIMISTIC。
TYPE_WARNING:指定游标从所请求的类型隐式转换为另外一种类型时,向客户端发送警告消息。
select_statement:是定义游标结果集中的标准SELECT语句。
2.打开游标
使用游标以前, 须要打开游标:
OPEN [ GLOBAL ] cursor_name | cursor_variable_name;
说明:
GLOBAL:指定cursor_name是全局游标。
cursor_name:已声明的游标的名称。若是全局游标和局部游标都使用cursor_name做为其名称,那么若是指定了GLOBAL,则cursor_name指的是全局游标,不然cursor_name指的是局部游标。
cursor_variable_name:游标变量的名称。
3.读取游标中的数据
打开游标以后就能够读取游标中的数据了, fetch 命令能够读取游标中的某一行数据,fetch的语法:
ETCH [ [ NEXT | PRIOR | FIRST | LAST | ABSOLUTE { n | @nvar } | RELATIVE { n | @nvar } ] FROM ] { { [GLOBAL ] cursor_name } | @cursor_variable_name} [ INTO @variable_name [ ,...n ] ]
说明:
NEXT: 紧跟当前行返回结果行,而且当前行递增为返回行,若是FETCH NEXT为对游标的第一次提取操做,则返回结果集中的第一行。NEXT为默认的游标提取选项。
PRIOR:返回紧邻当前行前面的结果行,而且当前行递减为返回行,若是FETCH PRIOR为对游标的第一次提取操做,则没有行返回而且游标置于第一行以前。
FIRST:返回游标中的第一行并将其做为当前行。
LAST:返回游标中的最后一行并将其做为当前行。
ABSOLUTE { n | @nvar }:若是n或@nvar为正,则返回从游标头开始向后n行的第n行,并将返回行变成新的当前行。若是n或@nvar为负,则返回从游标末尾开始向前的n行的第n行,并将返回行变成新的当前行。若是n或@nvar为0,则不返回行。n必须是整数常量,而且@nvar的数据类型必须为int、tinyint或smallint.
RELATIVE { n | @nvar }:若是n或@nvar为正,则返回从当前行开始向后的第n行。若是n或@nvar为负,则返回从当前行开始向前的第n行。若是n或@nvar为0,则返回当前行,对游标第一次提取时,若是在将n或@nvar设置为负数或0的状况下指定FETCH RELATIVE,则不返回行,n必须是整数常量,@nvar的数据类型必须是int、tinyint或smallint.
GLOBAL:指定cursor_name是全局游标。
cursor_name:已声明的游标的名称。若是全局游标和局部游标都使用cursor_name做为其名称,那么若是指定了GLOBAL,则cursor_name指的是全局游标,不然cursor_name指的是局部游标。
@cursor_variable_name:游标变量名,引用要从中进行提取操做的打开的游标。
INTO @variable_name [ ,...n ]:容许将提取操做的列数据放到局部变量中。列表中的各个变量从左到右与游标结果集中的相应列相关联。各变量的数据类型必须与相应的结果集列的数据类型相匹配,或是结果集列数据类型所支持的隐士转换。变量的数目必须与游标选择列表中的列数一致
4.关闭游标
SQL Server 在打开游标以后, 服务器会专门为游标开辟必定的内存空间存放游标操做的数据结果集,同时游标的使用也会根据具体状况对某些数据进行封锁。因此在不使用游标的时候,能够将其关闭 ,已释放游标所占用的服务器资源,关闭游标使用close 语句。
CLOSE [ GLOBAL ] cursor_name | cursor_variable_name
5.释放游标
游标操做的结果集空间虽然释放了,可是游标自己也会占用必定的计算集资源,因此在使用完游标以后, 为了收回被游标占用的资源, 应该将游标释放。释放游标使用deallocate语句。
DEALLOCATE [GLOBAL] cursor_name | @ccursor_variable_name
@ccursor_variable_name:游标变量的名称,@ccursor_variable_name必须为cursor类型。
DEALLOCATE @ccursor_variable_name 语句只删除对游标变量名称的引用,直到批处理、存储过程或触发器结束时变量离开做用域,才释放变量。
DECLARE BookOID_Cursor CURSOR FOR SELECT OID FROM T_Book_TX WHERE ReceivedDate < DATEADD(DAY, -@Xdays, GETDATE()); OPEN BookOID_Cursor; FETCH NEXT FROM BookOID_Cursor INTO @BookOID; WHILE @@FETCH_STATUS = 0 BEGIN EXEC P_UpdateBookByOID @BookOID; FETCH NEXT FROM BookOID_Cursor INTO @BookOID; END; CLOSE BookOID_Cursor; DEALLOCATE BookOID_Cursor;
1.使用游标变量
声明变量用DECLARE,为变量赋值能够用set或SELECT语句,对于游标变量的声明和赋值,其操做基本相同。在具体使用时,首先要建立一个游标,将其打开后,将游标的值赋给游标变量,并经过FETCH语句从游标变量中读取值,最后关闭释放游标。
【例】声明名称为@varCursor的游标变量,输入以下:
DECLARE @varCursor Cursor --声明游标变量 DECLARE cursor_fruit CURSOR FOR --建立游标 SELECT f_name,f_price FROM fruits; OPEN cursor_fruit --打开游标 SET @varCursor=cursor_fruit --为游标变量赋值 FETCH NEXT FROM @varCursor --从游标变量中读取值 WHILE @@FETCH_STATUS=0 --判断FETCH语句是否执行成功 BEGIN FETCH NEXT FROM @varCursor --读取游标变量中的数据 END CLOSE @varCursor --关闭游标 DEALLOCATE @varCursor; --释放游标
2.用游标为变量赋值
在游标的操做过程当中,可使用FETCH语句将数据值存入变量,这些保持表中列值的变量能够在后面的程序中使用。
【例】建立游标cursor_variable,将fruits表中的记录f_name,f_price值赋给变量@fruitName和@fruitPrice,并打印输出。
--建立游标cursor_variable,将fruits表中的记录f_name,f_price值赋给变量@fruitName和@fruitPrice DECLARE @fruitName varchar(50),@fruitPrice Decimal(8,2) DECLARE cursor_variable CURSOR FOR SELECT f_name,f_price FROM fruits WHERE f_id<100; OPEN cursor_variable FETCH NEXT FROM cursor_variable INTO @fruitName,@fruitPrice PRINT 'Fruit Name and Fruit Price is:' WHILE @@FETCH_STATUS=0 BEGIN PRING @fruitName+' '+STR(@fruitPrice,8,2) FETCH NEXT FROM cursor_variable INTO @fruitName,@fruitPrice END CLOSE cursor_variable; DECALLOCATE cursor_variable;
3.用ORDER BY 子句改变游标中的执行顺序
游标是一个查询结果集,那么能不能对结果进行排序呢?答案是否认的。与基本的SELECT语句中的排序方法相同,ORDER BY子句添加到查询中能够对游标查询的结果排序。
注意:只有出如今游标中的SELECT语句中的列才能做为ORDER BY 子句的排序列,而对与非游标的SELECT语句中,表中任何列均可以做为ORDER BY 的排序列,即便该列没有出如今SELECT语句的查询结果列中。
【例】声明名称为cursor_order的游标,对fruits表中的记录按照价格字段降序排列,输入语句以下:
--建立游标cursor_order的游标,将fruits表中的记录按照价格排序 DECLARE cursor_order CURSOR FOR SELECT f_name,f_price FROM fruits WHERE f_id<100 ORDER BY f_price DESC; OPEN cursor_order FETCH NEXT FROM cursor_order WHILE @@FETCH_STATUS=0 FETCH NEXT FROM cursor_order CLOSE cursor_variable DECALLOCATE cursor_variable
4.用游标修改数据
【例】声明整型变量@fid=99,而后声明一个对fruits表进行操做的游标,打开该游标,使用FETCH NEXT方法来获取游标中的每一行的数据,若是获取到的记录的f_id的字段值与@sid值相同,将f_id=@fid的记录中的f_price修改成500,最后关闭释放游标,输入以下:
--使用FETCH NEXT 方法来获取游标中的每一行数据 --若是获取到的记录的f_id 与@id相同,则将价格改成500 DECLARE @id INT = 99,@fid INT DECLARE cursor_fruit CURSOR FOR SELECT f_id FROM fruits; OPEN cursor_fruit FETCH NEXT FROM cursor_fruit INTO @fid WHILE @@FETCH_STATUS=0 BEGIN IF @fid=@id update fruits set f_price=500 where f_id=@id FETCH NEXT FROM cursor_variable INTO @fid END CLOSE cursor_fruit; DECALLOCATE cursor_fruit;
5.用游标删除数据
使用游标删除数据时,既能够删除游标结果集中的数据,也能够删除基本表中的数据
【例】使用游标删除fruits表中s_id=102的记录,以下:
--【例】使用游标删除fruits表中s_id=102的记录,以下 DECLARE @sid1 INT,@id1 int=102 DECLARE cursor_delete CURSOR FOR SELECT s_id FROM fruits; OPEN cursor_delete FETCH NEXT FROM cursor_delete INTO @sid1 WHILE @@FETCH_STATUS=0 BEGIN IF @sid1=@id1 BEGIN DELETE FROM fruits where s_id=@id1 END FETCH NEXT FROM cursor_delete INTO @sid1 END CLOSE cursor_delete DEALLOCATE cursor_delete; SELECT * FROM fruits where s_id=102;