SQL Server游标

本文详细介绍了SQL Server中游标的基本概念、分类、生命周期及其具体应用。包括如何声明、打开、读取、更新、关闭和释放游标等操作,并提供了丰富的示例代码。

转载自:http://www.cnblogs.com/knowledgesea/p/3699851.html。

什么是游标                                                                                   

结果集,结果集就是select查询之后返回的所有行数据的集合。

游标则是处理结果集的一种机制吧,它可以定位到结果集中的某一行,多数据进行读写,也可以移动游标定位到你所需要的行中进行操作数据。

一般复杂的存储过程,都会有游标的出现,他的用处主要有:

  1. 定位到结果集中的某一行。
  2. 对当前位置的数据进行读写。
  3. 可以对结果集中的数据单独操作,而不是整行执行相同的操作。
  4. 是面向集合的数据库管理系统和面向行的程序设计之间的桥梁。

游标的分类                                                                                    

根据游标检测结果集变化的能力和消耗资源的情况不同,SQL Server支持的API服务器游标分为一下4种:

  • 静态游标: 静态游标的结果集,在游标打开的时候建立在TempDB中,不论你在操作游标的时候,如何操作数据库,游标中的数据集都不会变。例如你在游标打开的时候,对游标查询的数据表数据进行增删改,操作之后,静态游标中select的数据依旧显示的为没有操作之前的数据。如果想与操作之后的数据一致,则重新关闭打开游标即可。
  • 动态游标:这个则与静态游标相对,滚动游标时,动态游标反应结果集中的所有更改。结果集中的行数据值、顺序和成员在每次提取时都会变化。所有用户做的增删改语句通过游标均可见。如果使用API函数或T-SQL Where Current of子句通过游标进行更新,他们将立即可见。在游标外部所做的更新直到提交时才可见。
  • 只进游标:只进游标不支持滚动,只支持从头到尾顺序提取数据,数据库执行增删改,在提取时是可见的,但由于该游标只能进不能向后滚动,所以在行提取后对行做增删改是不可见的。
  • 键集驱动游标:打开键集驱动游标时,该有表中的各个成员身份和顺序是固定的。打开游标时,结果集这些行数据被一组唯一标识符标识,被标识的列做删改时,用户滚动游标是可见的,如果没被标识的列增该,则不可见,比如insert一条数据,是不可见的,若可见,须关闭重新打开游标。

静态游标在滚动时检测不到表数据变化,但消耗的资源相对很少。动态游标在滚动时能检测到所有表数据变化,但消耗的资源却较多。键集驱动游标则处于他们中间,所以根据需求建立适合自己的游标,避免资源浪费。

游标的生命周期                                                                             

游标的生命周期包含有五个阶段:声明游标、打开游标、读取游标数据、关闭游标、释放游标。

 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 3 from orderNum_02_cursor
fetch next from orderNum_02_cursor
fetch absolute 4 from 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 3 from 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语句失败或行不在结果集中。-2:提取的行不存在。

这个状态值可以帮你判断提取数据的成功与否。

复制代码
declare @OrderId int
fetch absolute 3 from 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

转载于:https://www.cnblogs.com/yoga21/p/8922364.html

<think>我们参考了引用内容,其中[^1]强调了在SQL中应优先考虑基于集合的操作而非游标,因为游标是逐行处理,效率较低;[^2]则给出了一个静态游标的使用示例。用户明确询问SQLServer游标的使用教程或常见问题解决方案,因此我们将从以下几个方面构建回答:1.游标的基本概念与类型:解释游标是什么,静态游标、动态游标等类型区别2.游标的使用步骤:声明、打开、获取数据、循环处理、关闭释放3.游标的适用场景和替代方案:说明何时应避免使用游标,以及替代方案(如基于集合的操作)4.常见问题解决方案:例如游标性能优化、避免死锁等根据引用[^2]的示例代码,我们给出一个更详细的游标使用示例,并加入中文注释。同时,根据用户需求,生成相关问题。</think> ### SQL Server 游标使用指南 #### 一、游标基本概念 游标(Cursor)是SQL Server中用于**逐行处理查询结果**的数据库对象。与基于集合的操作不同,游标允许逐行访问数据,适用于需要精细控制的场景[^1]。但需注意: - **优先使用集合操作**:SQL设计核心是基于集合的操作,游标会降低性能(尤其大数据量时) - **适用场景有限**:仅当无法用单条SQL实现时才考虑游标 #### 二、游标类型对比 | 类型 | 特点 | |--------------|----------------------------------------------------------------------| | **静态游标** | 创建时复制数据快照,不反映后续数据修改(`STATIC`) | | **动态游标** | 实时反映数据变化(默认类型,需显式声明`DYNAMIC`) | | **键集驱动** | 仅跟踪主键变化(`KEYSET`) | > 参考:[^2]中博主"二月十六"的《SQL SERVER 游标使用》详细区别 #### 三、游标使用教程 1. **声明游标** ```sql DECLARE my_cursor CURSOR STATIC -- STATIC静态/DYNAMIC动态 FOR SELECT name, id FROM users WHERE status=1 -- 查询逻辑 ``` 2. **打开与操作游标** ```sql -- 声明变量 DECLARE @name VARCHAR(50), @id INT OPEN my_cursor -- 打开游标 -- 循环读取数据 FETCH NEXT FROM my_cursor INTO @name, @id WHILE @@FETCH_STATUS = 0 -- 成功获取数据 BEGIN -- 业务逻辑(示例:打印+更新) PRINT '处理用户: ' + @name UPDATE orders SET processed=1 WHERE user_id=@id FETCH NEXT FROM my_cursor INTO @name, @id -- 获取下一行 END ``` 3. **关闭与释放资源** ```sql CLOSE my_cursor -- 关闭游标 DEALLOCATE my_cursor -- 释放内存资源 ``` #### 四、常见问题解决方案 1. **性能优化** - 使用`FAST_FORWARD`只进游标(轻量级) - 限制处理行数(添加`TOP`子句) - 替代方案:尝试用`WHILE`循环或CTE递归 2. **@@FETCH_STATUS异常处理** ```sql IF @@FETCH_STATUS = -1 -- 无数据 PRINT '游标数据已读完' IF @@FETCH_STATUS = -2 -- 行被删除 PRINT '当前行已被删除,跳过处理' ``` 3. **死锁避免** - 操作前加`WITH (NOLOCK)`提示(脏读风险) - 缩短事务时间:在循环内提交小事务 4. **动态SQL整合** ```sql DECLARE @sql NVARCHAR(MAX) = 'SELECT * FROM products' DECLARE my_cursor CURSOR FOR EXEC sp_executesql @sql -- 动态SQL支持 ``` #### 五、使用建议 1. **避免场景**:批量更新/聚合计算(改用`UPDATE FROM`或窗口函数) 2. **必须使用场景**: - 逐行调用存储过程 - 级联操作(如根据A表结果动态修改B表) 3. **资源管理**:务必在结束时关闭游标,防止内存泄漏 > 关键原则:**能用集合操作解决的问题,绝对不用游标**[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值