SQL游标(cursor)详细说明及内部循环使⽤⽰例
游标
  游标(cursor)是系统为⽤户开设的⼀个数据缓冲区,存放SQL语句的执⾏结果。每个游标区都有⼀个名字,⽤户可以⽤SQL语句逐⼀从游标中获取记录,并赋给主变量,交由主语⾔进⼀步处理。
  游标是处理结果集的⼀种机制吧,它可以定位到结果集中的某⼀⾏,多数据进⾏读写,也可以移动游标定位到你所需要的⾏中进⾏操作数据。⼀般复杂的存储过程,都会有游标的出现,他的⽤处主要有:
1. 定位到结果集中的某⼀⾏。
2. 对当前位置的数据进⾏读写。
3. 可以对结果集中的数据单独操作,⽽不是整⾏执⾏相同的操作。
4. 是⾯向集合的数据库管理系统和⾯向⾏的程序设计之间的桥梁。
优点
  在数据库中,游标是⼀个⼗分重要的概念。游标提供了⼀种对从表中检索出的数据进⾏操作的灵活⼿段,
就本质⽽⾔,游标实际上是⼀种能从包括多条数据记录的结果集中每次提取⼀条记录的机制。游标总是与⼀条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 游标使⽤在服务器端,所以被称为服务器游标,也被称为后台游标,⽽客户端游标被称为前台游标。在本章中我们主要讲述服务器(后台)游标。游标的分类
  根据游标检测结果集变化的能⼒和消耗资源的情况不同,SQL Server⽀持的API服务器游标分为⼀下4种:
静态游标 : 静态游标的结果集,在游标打开的时候建⽴在TempDB中,不论你在操作游标的时候,如何操作数据库,游标中的数据集都不会变。例如你在游标打开的时候,对游标查询的数据表数据进⾏增删改,操作之后,静态游标中select的数据依旧显⽰的为没有操作之前的数据。如果想与操作之后的数据⼀致,则重新关闭打开游标即可。
动态游标 : 这个则与静态游标相对,滚动游标时,动态游标反应结果集中的所有更改。结果集中的⾏数据值、顺序和成员在每次提取时都会变化。所有⽤户做的增删改语句通过游标均可见。如果使⽤API函数或T-SQL Where Current of⼦句通过游标进⾏更新,他们将⽴即可见。在游标外部所做的更新直到提交时才可见。
只进游标:只进游标不⽀持滚动,只⽀持从头到尾顺序提取数据,数据库执⾏增删改,在提取时是可见的,但由于该游标只能进不能向后滚动,所以在⾏提取后对⾏做增删改是不可见的。
键集驱动游标:打开键集驱动游标时,该有表中的各个成员⾝份和顺序是固定的。打开游标时,结果集这些⾏数据被⼀组唯⼀标识符标识,被标识的列做删改时,⽤户滚动游标是可见的,如果没被标识的列增该,则不可见,⽐如insert⼀条数据,是不可见的,若可见,须关闭重新打开游标。静态游标在滚动时检测不到表数据变化,但消耗的资源相对很少。动态游标在滚动时能检测到所有表数据变化,但消耗的资源却较多。键集驱动游标则处于他们中间,所以根据需求建⽴适合⾃⼰的游标,避免资源浪费。
游标的⽣命周期
  游标的⽣命周期包含有五个阶段:声明游标、打开游标、读取游标数据、关闭游标、释放游标。mysql语句的执行顺序
1,声明游标
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 ] ] ]
参数说明:
cursor_name:游标名称。
Local:作⽤域为局部,只在定义它的批处理,存储过程或触发器中有效。
Global:作⽤域为全局,由连接执⾏的任何存储过程或批处理中,都可以引⽤该游标。
[Local | Global]:默认为local。
Forward_Only:指定游标智能从第⼀⾏滚到最后⼀⾏。Fetch Next是唯⼀⽀持的提取选项。如果在指定Forward_Only是不指定Static、KeySet、Dynamic关键字,默认为Dynamic游标。如果Forward_Only和Scroll没有指定,Static、KeySet、Dynamic游标默认为Scroll,Fast_Forward默认为Forward_Only
Static:静态游标
KeySet:键集游标
Dynamic:动态游标,不⽀持Absolute提取选项
Fast_Forward:指定启⽤了性能优化的Forward_Only、Read_Only游标。如果指定啦Scroll或For_Update,就不能指定他啦。
Read_Only:不能通过游标对数据进⾏删改。
Scroll_Locks:将⾏读⼊游标是,锁定这些⾏,确保删除或更新⼀定会成功。如果指定啦Fast_Forward或Static,就不能指定他啦。
Optimistic:指定如果⾏⾃读⼊游标以来已得到更新,则通过游标进⾏的定位更新或定位删除不成功。当将⾏读⼊游标时,sqlserver不锁定⾏,它改⽤timestamp列值的⽐较结果来确定⾏读⼊游标后是否发⽣了修改,如果表不⾏timestamp列,它改⽤校验和值进⾏确定。如果已修改改⾏,则尝试进⾏的定位更新或删除将失败。如果指定啦Fast_Forward,则不能指定他。
Type_Warning:指定将游标从所请求的类型隐式转换为另⼀种类型时向客户端发送警告信息。
For Update[of column_name ,....] :定义游标中可更新的列。
2,声明⼀个动态游标
declare orderNum_02_cursor cursor scroll
for select OrderId from bigorder where orderNum='ZEORD003402'
3,打开游标
--打开游标语法
open[ Global ] cursor_name | cursor_variable_name
cursor_name:游标名,cursor_variable_name:游标变量名称,该变量引⽤了⼀个游标。
--打开游标
open orderNum_02_cursor
4,提取数据
-
-提取游标语法
Fetch
[ [Next|prior|Frist|Last|Absoute n|Relative n ]
from ]
[Global] cursor_name
[into @variable_name[,....]]
参数说明:
Frist:结果集的第⼀⾏
Prior:当前位置的上⼀⾏
Next:当前位置的下⼀⾏
Last:最后⼀⾏
Absoute n:从游标的第⼀⾏开始数,第n⾏。
Relative n:从当前位置数,第n⾏。
Into @variable_name[,...] : 将提取到的数据存放到变量variable_name中。
例⼦:
--提取数据
fetch first from orderNum_02_cursor
fetch relative 3from orderNum_02_cursor
fetch next from orderNum_02_cursor
fetch absolute 4from orderNum_02_cursor
fetch next from orderNum_02_cursor
fetch last from orderNum_02_cursor
fetch prior from orderNum_02_cursor
select*from bigorder where orderNum='ZEORD003402'
例⼦:
--提取数据赋值给变量
declare@OrderId int
fetch absolute 3from orderNum_02_cursor into@OrderId
select@OrderId as id
select*from bigorder where orderNum='ZEORD003402'
通过检测全局变量@@Fetch_Status的值,获得提取状态信息,该状态⽤于判断Fetch语句返回数据的有效性。当执⾏⼀条Fetch语句之后,@@Fetch_Status可能出现3种值:0,Fetch语句成功。
-1:Fetch语句失败或⾏不在结果集中。
accesstoken与appkey不匹配
-2:提取的⾏不存在。
这个状态值可以帮你判断提取数据的成功与否。
declare@OrderId int
fetch absolute 3from orderNum_02_cursor into@OrderId
while@@fetch_status=0--提取成功,进⾏下⼀条数据的提取操作
begin
select@OrderId as id
fetch next from orderNum_02_cursor into@OrderId--移动游标
end
5.利⽤游标更新删除数据
--游标修改当前数据语法
Update基表名Set列名=值[,...]Where Current of游标名
-
-游标删除当前数据语法
Delete基表名Where Current of游标名
游标更新删除当前数据
--1.声明游标
declare orderNum_03_cursor cursor scroll
for select OrderId ,userId from bigorder where orderNum='ZEORD003402'
--2.打开游标
open orderNum_03_cursor
--3.声明游标提取数据所要存放的变量
declare@OrderId int ,@userId varchar(15)
--4.定位游标到哪⼀⾏
fetch First from orderNum_03_cursor into@OrderId,@userId--into的变量数量必须与游标查询结果集的列数相同
while@@fetch_status=0--提取成功,进⾏下⼀条数据的提取操作
begin
if@OrderId=122182
begin
Update bigorder Set UserId='123'Where Current of  orderNum_03_cursor  --修改当前⾏
对象突然对自己冷淡了怎么办end
if@OrderId=154074
begin
Delete bigorder Where Current of  orderNum_03_cursor  --删除当前⾏
end
fetch next from orderNum_03_cursor into@OrderId ,@userId--移动游标
end
6,关闭游标
  游标打开后,服务器会专门为游标分配⼀定的内存空间存放游标操作的数据结果集,同时使⽤游标也会对某些数据进⾏封锁。所以游标⼀旦⽤过,应及时关闭,避免服务器资源浪费。
--关闭游标语法
close[ Global ] cursor_name | cursor_variable_name
--关闭游标
close orderNum_03_cursor
7,删除游标
  删除游标,释放资源
--释放游标语法
deallocate[ Global ] cursor_name | cursor_variable_name
--释放游标
deallocate orderNum_03_cursor
使⽤实例:
USE Test_DB;
DECLARE@jid CHAR(5)
construction drawingDECLARE@pic NVARCHAR(64)
DECLARE My_Cursor CURSOR--定义游标
FOR (SELECT jid FROM journal WHERE isall in(1,2)) --查出需要的集合放到游标中
OPEN My_Cursor; --打开游标
FETCH NEXT FROM My_Cursor INTO@jid; --读取第⼀⾏数据
WHILE@@FETCH_STATUS=0
BEGIN
SET@pic=(SELECT TOP1 smallpic FROM journalissue WHERE jid=@jid and (smallpic !=''and smallpic is not null) ORDER BY issueyear DESC,issueno DESC);
PRINT (@jid+''+@pic);
IF(@jid!=''and@jid is not null and@pic!=''and@pic is not null)
BEGIN
UPDATE journal SET pic=@pic WHERE jid=@jid;
END
FETCH NEXT FROM My_Cursor INTO@jid; --读取下⼀⾏数据
END
CLOSE My_Cursor; --关闭游标
DEALLOCATE My_Cursor; --释放游标
GO
详细说明
RS.OPEN SQL,CONN,A,B
参数A为设定游标的类型,其取值为: 0 仅向前游标,只能向前浏览记录,不⽀持分页、Recordset、BookMark
1 键集游标,其他⽤户对记录所做的修改将反映到记录集中,但其他⽤户增加或删除记录不会反映到记录集中。⽀持分页、Recordset、BookMark
2 动态游标功能最强,但耗资源也最多。⽤户对记录所做的修改,增加或删除记录都将反映到记录集中。⽀持全功能浏览。
3 静态游标,只是数据的⼀个快照,⽤户对记录所做的修改,增加或删除记录都不会反映到记录集中。⽀持向前或向后移动
参数B为记录集的锁定类型,其取值为:
1 锁定类型,默认的,只读,不能作任何修改
2 当编辑时⽴即锁定记录,最安全的⽅式
3 只有在调⽤Update⽅法时才锁定记录集,⽽在此前的其他操作仍可对当前记录进⾏更改、插⼊和删除等
4 当编辑时记录不会被锁定,⽽更改、插⼊和删除是在批处理⽅式下完成的
打开数据记录集⽅法其实不⽌⼀种,但是我们⽤的最多的就是
rs.open sql,1,1的⽅法,可是后⾯的数字参数很多⼈不解其意,下⾯我们来介绍⼀下。
其实open⽅法后⾯有多个参数
CursorType LockType CommandType
⽐如 rs.open sql,1,1
也可以写成
rs.cursorType = 1
阿根廷小组赛积分
rs.LockType = 1
rs.open sql
其中CursorType代表从⼀个表或者⼀个SQL查询结果返回的记录。
这个参数有四个值分别是:
adOpenForwardOnly 表⽰只允许在记录集内的记录间往前移动。这个是缺省值。
adOpenKeyset 反映由其它⽤户所做的对记录的改变或者删除动作,但并不反映由其它⽤户做作的添加新记录的动作。
adOpenDynamic 反映由其它⽤户所做的对记录的改变或者删除动作,包括添加的新记录
adOpenStatic 不反映其它⽤户对记录所做的修改,添加,删除动作。
这四个值VBSCRIPT预定义位
adOpenForwardOnly = 0
adOpenKeyset = 1
adOpenDynamic = 2
adOpenStatic = 3
lockType 表⽰当打开记录集时,数据提供者⽤于锁定数据库的类型:
adLockReadOnly 数据不能改变,这是缺省值!
adLockPessimistic 数据提供者在开始编辑数据的时候锁定记录
adLockOptimistic 仅当调⽤update⽅法时,数据提供者锁定记录
adLockBatchOptimistic ⽤于批处理修改
他们的常量值定义分别是:
adLockReadOnly = 1
adLockPessimistic = 2
adLockOptimistic = 3
adLockBatchOptimistic = 4
rs.open sql,conn,1,1 读取记录 select
rs.open sql,conn,1,3 只更新记录最好 update
rs.open sql,conn,2,3 插⼊和删除最好 insert delete
⽰例:
1USE[Community];
2
3DECLARE@UserInfoID bigint,@Name nvarchar(100),@UCAccountID bigint;
4
5
sizeof和strlen区别实例6DECLARE My_Cursor CURSOR--定义游标
7FOR (
8select distinct(UI.[UserInfoID]),UI.[Name],UIToUC.[UCAccountID]from[dbo].[CMAreaRelation]as AR
9inner join[dbo].[UserInfo]as UI on UI.[UserInfoID]=AR.[Creator]
10inner join[dbo].[UserInfoToUCAccount]as UIToUC on UIToUC.[UserInfoID]=UI.[UserInfoID]
11 ) --查出需要的集合放到游标中
12OPEN My_Cursor; --打开游标
13FETCH NEXT FROM My_Cursor INTO@UserInfoID,@Name,@UCAccountID; --读取第⼀⾏数据
14WHILE@@FETCH_STATUS=0
15BEGIN
16PRINT'@UserInfoID='+convert(varchar,isnull(@UserInfoID,0))+', @Name='+isnull(@Name,'')+', @UCAccountID='+convert(varchar,isnull(@UCAccountID,0)); --打印,⽅便查看(正式项⽬不需要该⾏)17--这⾥是根据每⼀⾏编写⾃定义的操作……
18
19FETCH NEXT FROM My_Cursor INTO@UserInfoID,@Name,@UCAccountID; --读取下⼀⾏数据
20END
21CLOSE My_Cursor; --关闭游标
22DEALLOCATE My_Cursor; --释放游标
23GO

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。