SQLSERVER 中的游标

SQLSERVER 中的游标

                   在关系数据库中,传统的查询是面向结果集的,如果你想一行一行的读取数据并做相关的处理,那么你就要用到游标(像for循环一样,允许你一行一行的读取数据) 能不用游标就不用游标,在性能上,游标会吃更多的内存,减少可用的并发,占用宽带,锁定资源,当然还有更多的代码量……

      总之:

     1.现存系统有一些游标,我们查询必须通过游标来实现

     2.作为一个备用方式,当我们穷尽了while循环,子查询,临时表,表变量,自建函数或其他方式扔来无法实现某些查询的时候,使用游标实现.游标的使用可以很简单,也可以相对复杂,取决与对游标的参数,和你对他的了解程度

   基本语法:

                DECLARE CURSOR_NAME CURSOR 

                LOCAL|GLOBAL

                STATIC|KEYSET|DYNAMIC|FAST_FORWARD

                READ_ONLY|SCROLL_LOCKS|OPTIMISTIC

                TYPE_WARNING

                FOR

                SELECT * FROM TABLE

                FOR UPDATE OF COLUMN_NAME

接下来一一的讲解,每个参数具体的含义和使用方法。

 LOCAL 和GLOBAL 

 LOCAL 意思就是游标的生存周期只在批处理函数或存储过程中可见;

 GOBAL 意味着对于特定连接的上下文,全局内都有效的呀;

 FORWARD_ONLY 和 SCROLL 

 FORWARD_ONLY 意思就是说只能从数据集开始向结束的方向读取,FETCH NEXT是唯一的搭档;

 SCROLL  任意方向 或位置

STATIC KEYSET DYNAMIC FAST_FORWARD

STATIC 意思是说,当游标建立的时候,将会创建for后面的select语句所包含数据集的副本存入tempdb数据库中,任何对底层数据的更改不会影响到游标的读取。

DYNAMIC 当底层数据更改的时候,游标的内容也随之反映上来。

KEYSET  以理解为介于STATIC和DYNAMIC的折中方案。将游标所在结果集的唯一能确定每一行的主键存入tempdb,当结果集中任何行改变或者删除时,@@FETCH_STATUS会为-2,KEYSET无法探测新加入的数据

FAST_FORWARD :......

READ_ONLY SCROLL_LOCKS OPTIMISTIC

READ_ONLY  意味着声明的游标只能读取数据,游标不能做任何更新操作

SCROLL_LOCKS  将读入游标的所有数据进行锁定,防止其他程序进行更改,以确保更新的绝对成功

OPTIMISTIC 不锁定任何数据,当需要在游标中更新数据时,如果底层表数据更新,则游标内数据更新不成功,如果,底层表数据未更新,则游标内表数据可以更新

游标的定义: 

--定义后直接赋值
   DECLARE CUR CURSOR
   FOR
   SELECT * FROM CITYINFO

--先定义后赋值
   DECLARE @CUR CURSOR
   SET @CUR=CURSOR FOR
   SELECT * FROM CITYINFO
 

游标的打开,关闭,释放

   OPEN CURSOR_NAME       --打开游标
   
   CLOSE CURSOR_NAME       --可能会再次使用到,就暂时关闭
   
   DEALLOCATE CURSOR_NAME  --当游标不再使用的时候

具体的实例一

    

--定义后直接赋值
   DECLARE CUR CURSOR
   LOCAL                --本地
   STATIC               --静态
   FORWARD_ONLY         --单向
   READ_ONLY            --只读
   FOR
   SELECT NAME FROM CITYINFO
   
   OPEN CUR
   DECLARE @RESULT VARCHAR(30)
   FETCH NEXT FROM CUR INTO @RESULT
   PRINT @RESULT
   WHILE(@@FETCH_STATUS=0)  --@@FETCH_STATTIC 默认为-1 读取成功一次后为 0 读取完后 为-1 
   BEGIN                    --循环会多读取一次 出现重复
   FETCH NEXT FROM CUR INTO @RESULT
   PRINT @RESULT
   END
   
   CLOSE CUR
   DEALLOCATE CUR

  结果:(注意最后一条)

 

具体实例二

   
 DECLARE CUR CURSOR
 LOCAL              --本地
 STATIC            --动态
 SCROLL             --滚动
 READ_ONLY          --只读
 FOR
     SELECT NAME FROM CITYINFO
 
 OPEN CUR
    DECLARE @RESULT VARCHAR(100)
    --取出下一行
    FETCH NEXT FROM CUR INTO @RESULT PRINT @RESULT
    --取出最后一行
    FETCH NEXT FROM CUR INTO @RESULT PRINT @RESULT
    --取出第一行
    FETCH FIRST FROM CUR INTO @RESULT PRINT @RESULT
    --取出上一行
    FETCH PRIOR FROM CUR INTO @RESULT PRINT @RESULT
    --取出第三行
    FETCH ABSOLUTE 3 FROM CUR INTO @RESULT PRINT @RESULT
    --取出相对目前来说的 上一行
    FETCH RELATIVE -1 FROM CUR INTO @RESULT PRINT @RESULT
    
  
    CLOSE CUR
    DEALLOCATE CUR    

还要注意一点:    

消息 16925,级别 16,状态 1,第 20 行
提取类型 Absolute 不能与动态游标一起使用。

更多的实例,还希望朋友们,自己动手测试一下。

对于游标一些优化建议

  •      如果能不用游标,尽量不要使用游标
  •      用完用完之后一定要关闭和释放
  •      尽量不要在大量数据上定义游标
  •      尽量不要使用游标上更新数据
  •      尽量不要使用insensitive, static和keyset这些参数定义游标
  •      如果可以,尽量使用FAST_FORWARD关键字定义游标
  •      如果只对数据进行读取,当读取时只用到FETCH NEXT选项,则最好使用FORWARD_ONLY参数
原文地址:https://www.cnblogs.com/mc67/p/4825367.html