T-SQL 游标的使用

游标相似于java中的循环操做。css

1.定义一个游标
游标其实能够理解成一个定义在特定数据集上的指针,咱们能够控制这个指针遍历数据集,或者仅仅是指向特定的行,因此游标是定义在以Select开始的数据集上的:java

T-SQL中的游标定义在MSDN中以下:
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 ] ] ]
[;]

这里写图片描述

二、游标定义的参数:
游标参数有:LOCAL和GLOBAL二选一,FORWARD_ONLY 和 SCROLL二选一,STATIC KEYSET DYNAMIC 和 FAST_FORWARD四选一,READ_ONLY SCROLL_LOCKS OPTIMISTIC 三选一
① LOCAL和GLOBAL
LOCAL意味着游标的生存周期只在批处理或函数或存储过程当中可见,而GLOBAL意味着游标对于特定链接做为上下文,全局内有效。若是不指定游标做用域,默认做用域为GLOBAL。web

--定义全局的游标,默认就是全局的
DECLARE test_cursor cursor global for select * from EnSummation;

--定义局部的游标
DECLARE test_cursor2 cursor local for select * from ExSummation;
--能够用来结束上面做用域
go

open test_cursor;

--此处打开会报错,由于test_cursor2是定义为局部的,go结束做用域后,局部的会报错
open test_cursor2;

② FORWARD_ONLY 和 SCROLL
FORWARD_ONLY意味着游标只能从数据集开始向数据集结束的方向读取,FETCH NEXT是惟一的选项,而SCROLL支持游标在定义的数据集中向任何方向,或任何位置移动。sql

--FORWARD_ONLY意味着游标只能从数据集开始向数据集结束的方向读取,只能搭配FETCH NEXT,默认为FORWARD_ONLY
DECLARE tst_cursor cursor  FORWARD_ONLY for select * from EnSummation;

--SCROLL支持游标在定义的数据集中向任何方向,或任何位置移动
DECLARE tst_cursor2 cursor SCROLL for select * from ExSummation;

open tst_cursor

open tst_cursor2

fetch next from tst_cursor

fetch last from tst_cursor -- 会报错,由于只能与fetch next一块儿使用

fetch next from tst_cursor2

fetch last from tst_cursor2

③ STATIC KEYSET DYNAMIC 和 FAST_FORWARD 四选一数据库

这四个关键字是游标所在数据集所反应的表内数据和游标读取出的数据的关系
STATIC意味着,当游标被创建时,将会建立FOR后面的SELECT语句所包含数据集的副本存入tempdb数据库中,任何对于底层表内数据的更改不会影响到游标的内容.
DYNAMIC是和STATIC彻底相反的选项,当底层数据库更改时,游标的内容也随之获得反映,在下一次fetch中,数据内容会随之改变
KEYSET能够理解为介于STATIC和DYNAMIC的折中方案。将游标所在结果集的惟一能肯定每一行的主键存入tempdb,当结果集中任何行改变或者删除时,@@FETCH_STATUS会为-2,KEYSET没法探测新加入的数据
FAST_FORWARD能够理解成FORWARD_ONLY的优化版本.FORWARD_ONLY执行的是静态计划,而FAST_FORWARD是根据状况进行选择采用动态计划仍是静态计划,大多数状况下FAST_FORWARD要比FORWARD_ONLY性能略好.
④ READ_ONLY SCROLL_LOCKS OPTIMISTIC 三选一
READ_ONLY意味着声明的游标只能读取数据,游标不能作任何更新操做
SCROLL_LOCKS是另外一种极端,将读入游标的全部数据进行锁定,防止其余程序进行更改,以确保更新的绝对成功
OPTIMISTIC是相对比较好的一个选择,OPTIMISTIC不锁定任何数据,当须要在游标中更新数据时,若是底层表数据更新,则游标内数据更新不成功,若是,底层表数据未更新,则游标内表数据能够更新svg

3.打开游标
当定义完游标后,游标须要打开后使用,只有简单一行代码:
OPEN test_Cursor
注意,当全局游标和局部游标变量重名时,默认会打开局部变量游标
4.关闭游标
在游标使用完以后,必定要记得关闭,只须要一行代码:CLOSE+游标名称
CLOSE test_Cursor函数

例子:性能

create Procedure [dbo].[proc_lanelistsum_initdata](@begin_date datetime,@end_date datetime) as declare @date datetime,--用来处理结果的变量 @formatSquad varchar(50), @v_desc varchar(500) begin set @v_desc = '处理的出口工班日期有:';
  --声明一个出口流水游标 
  Declare curSquaddateFee Cursor for   
  select squaddate from laneexlist_id where SquadDate between @begin_date and @end_date group by squaddate ---查询语句(查询当前的工班) --打开游标 Open curSquaddateFee --循环并提取记录 Fetch Next From curSquaddateFee Into @date--取第一条记录存入@result中 While ( @@Fetch_Status=0 ) begin set @formatSquad = CONVERT(varchar(10), @date, 23);--获取处理日期
        --删除出口汇总表当前工班为@@formatSquad的数据
        delete RepLaneExListSum where squaddate = @formatSquad;
        --从laneexlist表查询汇总squaddate 下的数据从新插入到汇总表中
        exec proc_laneexenlistSquaddate @formatSquad,2;
        --删除通行卡汇总表当前工班为@@formatSquad的数据 
        delete ys_PasscardviewSum where squaddate = @formatSquad and listtype in(2,3,4,5) --从laneexlist表查询汇总squaddate 下的数据从新插入到汇总表中 exec proc_laneexenlistSquaddate @formatSquad,4;
        set @v_desc = @v_desc + @formatSquad+',';
     Fetch Next From curSquaddateFee into @date----下一条 
       end --关闭游标 Close curSquaddateFee insert into EXEC_PROC_LOG(id,name,[description],[status],createtime) values(newid() ,'proc_lanelistsum-处理出口流水汇总表存储过程',@v_desc,1,GETDATE());
   set @v_desc = @v_desc + '入口工班日期有:';
  --释放游标 
   Deallocate curSquaddateFee 
 end;