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参数