SQL Server游标

什么是游标

结果集,结果集就是select查询以后返回的全部行数据的集合。sql

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

通常复杂的存储过程,都会有游标的出现,他的用处主要有:性能优化

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

游标的分类

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

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

静态游标在滚动时检测不到表数据变化,但消耗的资源相对不多。动态游标在滚动时能检测到全部表数据变化,但消耗的资源却较多。键集驱动游标则处于他们中间,因此根据需求创建适合本身的游标,避免资源浪费。。函数

游标的生命周期

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

 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 ] ] ]

参数说明:fetch

  • 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.打开游标spa

--打开游标语法
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
相关文章
相关标签/搜索