SQLServer游标详解
一、游标概念
我们知道,关系数据库所有的关系运算其实是集合与集合的运算,它的输入是集合输出同样是集合,有时需要对结果集逐行进行处理,这时就需要用到游标。我们对游标的使用一本遵循“五步法”:声明游标—>打开游标—>读取数据—>关闭游标—>删除游标。以下就从这五步对游标的使用进行说明,并给出具体实例。
二、“五步法”讲解
1、声明游标(DECLARE CURSOR)
(1) DECLARE CURSOR 既接受基于 ISO 标准的语法,也接受使用一组 Transact-SQL 扩展的语法。
ISO 语法
DECLARE cursor_name [ INSENSITIVE ] [ SCROLL ] CURSOR
FOR select_statement
[ FOR { READ ONLY | UPDATE [ OF column_name [ ,...n ] ] } ]
[;] Transact-SQL 扩展语法
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 ] ] ]
[;]
下面只对“T-SQL扩展语法”进行介绍,主要游标介绍作用域、方向及类型
(2)游标的作用域
LOCAL
说明所声明的游标为局部的,其作用域为创建它的批处理、存储过程或触发器,即在批处理、调用它的存储过程或触发器执行完成后,该游标被系统隐式释放。但,若游标作为存储过程OUTPUT 的输出参数,在存储过程终止后给游标变量分配参数可以继续引用游标,如果 OUTPUT 参数将游标传递回来,则游标在最后引用它的变量释放或离开作用域时释放。
GLOBAL
指定该游标的作用域对来说连接是全局的。在由连接执行的任何存储过程或批处理中,都可以引用该游标名称。该游标仅在断开连接时隐式释放。
注意:如果 GLOBAL 和 LOCAL 参数都未指定,则默认值由 default to local cursor 数据库选项的设置控制。在 SQL Server 7.0 版中,该选项默认为 FALSE,以便与 SQL Server 的早期版本匹配,在早期版本中,所有游标都是全局的。
declare testcur cursor --声明时未指定"local"或"global"关键字,系统默认游标是"global(全局)"的.
for
select 学号,姓名 from XSB
GO
open testcur
fetch next from testcur
GO
--------------------------------------------
declare testcur cursor local --声明时指定"local"关键字
for
select 学号,姓名 from XSB
open testcur
fetch next from testcur
GO --在这个批处理结束后,游标自动释放,即失效
-----------------------------------------------
declare testcur1 cursor local --声明时指定"local"关键字
for
select 学号,姓名 from XSB
GO --在这个批处理后,游标就失效了,后面对游标操作时,提示"名为 'testcur1' 的游标不存在"错误.
open testcur1
fetch next from testcur1
GO
(3)游标方向
FORWARD_ONLY
指定游标只能从第一行滚动到最后一行。FETCH NEXT 是唯一支持的提取选项。如果在指定 FORWARD_ONLY 时不指定 STATIC、KEYSET 和 DYNAMIC 关键字,则游标作为 DYNAMIC 游标进行操作。如果 FORWARD_ONLY 和 SCROLL 均未指定,则除非指定 STATIC、KEYSET 或 DYNAMIC 关键字,否则默认为 FORWARD_ONLY。STATIC、KEYSET 和 DYNAMIC 游标默认为 SCROLL。与 ODBC 和 ADO 这类数据库 API 不同,STATIC、KEYSET 和 DYNAMIC Transact-SQL 游标支持 FORWARD_ONLY。
SCROLL
指定所有的提取选项(FIRST、LAST、PRIOR、NEXT、RELATIVE、ABSOLUTE)均可用。如果未在 ISO DECLARE CURSOR 中指定 SCROLL,则 NEXT 是唯一支持的提取选项。如果也指定了 FAST_FORWARD,则不能指定 SCROLL。
declare directionCur cursor --不指定移动方向,则默认为“forward_only”
for
select 学号,姓名 from XSB
Go
open directionCur
fetch next from directionCur
Go
fetch prior from directionCur --错误“提取类型 prior 不能与只进游标一起使用。”
Go
close directionCur2
deallocate directionCur2
Go
-----------------------------------------
declare directionCur1 cursor forward_only --指定“forward_only”方向
for
select 学号,姓名 from XSB
Go
open directionCur1
fetch next from directionCur1
Go
fetch prior from directionCur1 --错误“提取类型 prior 不能与只进游标一起使用。”
Go
close directionCur2
deallocate directionCur2
Go
-----------------------------------------
declare directionCur2 cursor scroll --指定“scroll”方向
for
select 学号,姓名 from XSB
Go
open directionCur2
fetch next from directionCur2
Go
fetch prior from directionCur2
Go
close directionCur2
deallocate directionCur2
Go
---------------------------------
--结论:若游标没有指定任何访问或类型参数,则默认为全局、只进、动态游标。(这是在SQLServer2008 R2上的测试结果,具体取决于软件设置) --"scroll"和"fast_forward"不能一起使用
declare forwardTest cursor scroll fast_forward --报错“游标选项 SCROLL 和 FAST_FORWARD 冲突。”
for
select 学号,姓名 from XSB
Go --在 SQL Server 2000 中,FAST_FORWARD 和 FORWARD_ONLY 游标选项是互相排斥的。如果指定了二者,则会引发错误。
--在 SQL Server 2005 及更高版本中,这两个关键字可以用在同一个 DECLARE CURSOR 语句中。
declare forwardTest1 cursor forward_only fast_forward
for
select * from XSB
Go
(4)游标类型
STATIC
定义一个游标,以创建将由该游标使用的数据的临时复本。对游标的所有请求都从 tempdb 中的这一临时表中得到应答;因此,在对该游标进行提取操作时返回的数据中不反映对基表所做的修改,并且该游标不允许修改。及该游标是只读的。
KEYSET
指定当游标打开时,游标中行的成员身份和顺序已经固定。对行进行唯一标识的键集内置在 tempdb 内一个称为 keyset 的表中。
DYNAMIC
定义一个游标,以反映在滚动游标时对结果集内的各行所做的所有数据更改。行的数据值、顺序和成员身份在每次提取时都会更改。
FAST_FORWARD
指定启用了性能优化的 FORWARD_ONLY、READ_ONLY 游标。如果指定了 SCROLL 或 FOR_UPDATE,则不能也指定 FAST_FORWARD。
2、打开游标(OPEN)
语法
OPEN { { [ GLOBAL ] cursor_name } | cursor_variable_name }
示例
--打开游标并读取所有行
declare XSBcur cursor --声明
for
Select * from XSB
Go
open XSBcur --打开
fetch next from XSBcur --获取数据
while @@FETCH_STATUS = 0
begin
fetch next from XSBcur
end
close XSBcur --关闭
deallocate XSBcur --删除
全局变量 @@CURSOR_ROWS
该变量保存着最后打开的游标中的数据行数,当其值为0时,表示没有游标打开;其值为-1时,表示游标为动态的;当其值为-m(m为正整数)时,游标采用异步方式填充,m为当前键集中已填充的
行数;当其值为m(m为正整数)时,游标已被完全填充,m是游标中的数据行数。
3、读取数据
语法
FETCH
[ [ NEXT | PRIOR | FIRST | LAST
| ABSOLUTE { n | @nvar }
| RELATIVE { n | @nvar }
]
FROM
]
{ { [ GLOBAL ] cursor_name } | @cursor_variable_name }
[ INTO @variable_name [ ,...n ] ] --into说明将读取的游标数据存放到指定的变量中
示例
-----------------------------------
declare stuCur cursor scroll
for
select 学号,姓名 from XSB
GO
open stuCur
Go
--读取数据开始
fetch next from stuCur --读取当前行的下一行,并使其置为当前行(刚开始时游标置于表头的前一行,即若表是从0开始的,游标最初置于-1处,所以第一次读取的是头一行)
fetch prior from stuCur --读取当前行的前一行,并使其置为当前行
fetch first from stuCur --读取游标的第一行,并使其置为当前行(不能用于只进游标)
fetch last from stuCur --读取游标的最后一行,并使其置为当前行(不能用于只进游标)
fetch absolute 2 from stuCur --读取从游标头开始向后的第2行,并将读取的行作为新的行
fetch relative 3 from stuCur --读取从当前行开始向后的第3行,并将读取的行作为新的行
fetch relative-2 from stuCur --读取当前行的上两行,并将读取的行作为新的行
--读取数据结束
GO
close stuCur
Go
deallocate stuCur
Go
---------------------------
全局变量 @@FETCH_STATUS
FETCH语句的执行状态保存在全局变量@@FETCH_STATUS中,其值为0表示上一个FETCH执行成功;为-1表示所要读取的行不在结果集中;为-2表示被提取的行已不存在(已被删除)。
4、关闭游标(CLOSE)
语法
CLOSE { { [ GLOBAL ] cursor_name } | cursor_variable_name }
示例
close stuCur --若该游标事先声明并已打开
Go
5、删除游标(DEALLOCATE)
对游标进行操作的语句使用游标名称或游标变量引用游标。DEALLOCATE 删除游标与游标名称或游标变量之间的关联。如果一个名称或变量是最后引用游标的名称或变量,则将释放游标,游标使用的任何资源也随之释放。用于保护提取隔离的滚动锁在 DEALLOCATE 上释放。用于保护更新(包括通过游标进行的定位更新)的事务锁一直到事务结束才释放。
语法
DEALLOCATE { { [ GLOBAL ] cursor_name } | @cursor_variable_name }
示例
游标变量使用下列两种方法之一与游标关联:
--声明一个游标
declare abc cursor scroll
for
select * from XSB --(1)通过名称,使用set语句将游标设置为游标变量
declare @mycur cursor
set @mycur = abc --(2)也可以不定义游标名称而创建游标并将其与变量关联
declare @mycursor cursor
set @mycursor = cursor local scroll for
Select * from XSB
DEALLOCATE @cursor_variable_name 语句只删除对游标名称变量的引用。直到批处理、存储过程或触发器结束时变量离开作用域,才释放变量。在 DEALLOCATE @cursor_variable_name 语句之后,可以使用 SET 语句将变量与另一个游标关联。游标可以理解为指针。
declare @mycur cursor
set @mycur = cursor local scroll for
select * from XSB deallocate @mycur set @mycur = cursor local scroll for
select * from XSB
GO
--不必显式释放游标变量。变量在离开作用域时被隐式释放。
以下脚本显示游标如何持续到最后的名称或持续到引用它们的变量已释放。
USE AdventureWorks2008R2;
GO
-- Create and open a global named cursor that
-- is visible outside the batch.
DECLARE abc CURSOR GLOBAL SCROLL FOR
SELECT * FROM Sales.SalesPerson;
OPEN abc;
GO
-- Reference the named cursor with a cursor variable.
DECLARE @MyCrsrRef1 CURSOR;
SET @MyCrsrRef1 = abc;
-- Now deallocate the cursor reference.
DEALLOCATE @MyCrsrRef1;
-- Cursor abc still exists.
FETCH NEXT FROM abc;
GO
-- Reference the named cursor again.
DECLARE @MyCrsrRef2 CURSOR;
SET @MyCrsrRef2 = abc;
-- Now deallocate cursor name abc.
DEALLOCATE abc;
-- Cursor still exists, referenced by @MyCrsrRef2.
FETCH NEXT FROM @MyCrsrRef2;
-- Cursor finally is deallocated when last referencing
-- variable goes out of scope at the end of the batch.
GO
-- Create an unnamed cursor.
DECLARE @MyCursor CURSOR;
SET @MyCursor = CURSOR LOCAL SCROLL FOR
SELECT * FROM Sales.SalesTerritory;
-- The following statement deallocates the cursor
-- because no other variables reference it.
DEALLOCATE @MyCursor;
GO
三、用到的数据
1、创建表的脚本
CREATE TABLE [dbo].[XSB](
[学号] [char](6) NOT NULL,
[姓名] [char](8) NOT NULL,
[性别] [bit] NULL,
[出生时间] [date] NULL,
[专业] [char](12) NULL,
[总学分] [int] NULL,
[备注] [varchar](500) NULL,
PRIMARY KEY CLUSTERED
(
[学号] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] GO
2、插入数据
insert into XSB values
('','王林','true','1990-2-10','计算机',50,null),
('','陈平','true','1991-2-1','计算机',50,null),
('','王燕','false','1989-10-6','计算机',50,null),
('','韦严平','true','1990-8-26','计算机',50,null),
('','李芳芳','true','1990-11-20','计算机',50,null),
('','李明','true','1990-5-1','计算机',54,'已提前修完数据结构,并获学分'),
('','林一凡','true','1989-8-5','计算机',52,'已提前修完一门课'),
('','张强民','true','1989-8-11','计算机',50,null),
('','张蔚','false','1991-7-22','计算机',50,'三好生'),
('','赵琳','false','1989-10-6','计算机',50,null),
('','严红','false','1989-8-11','计算机',48,'一门不及格,待补考'),
('','王敏','true','1989-6-10','通信工程',42,null),
('','王林','true','1989-6-10','通信工程',40,'一门不及格,待补考')
GO
四、参考资料
http://technet.microsoft.com/zh-cn/library/ms181441(v=sql.105).aspx
SQLServer游标详解的更多相关文章
- SQLServer 游标详解
一.用到的数据 CREATE TABLE [dbo].[XSB]( ) NOT NULL, ) NOT NULL, [性别] [bit] NULL, [出生时间] [date] NULL, ) NUL ...
- SqlServer存储过程详解
SqlServer存储过程详解 1.创建存储过程的基本语法模板: if (exists (select * from sys.objects where name = 'pro_name')) dro ...
- Mysql高手系列 - 第19篇:mysql游标详解,此技能可用于救火
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 这是Mysql系列第19篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符 ...
- Oracle游标详解大全
本文出自: http://www.cnblogs.com/sc-xx/archive/2011/12/03/2275084.html -- 声明游标:CURSOR cursor_name IS sel ...
- Oracle学习笔记之游标详解
游标 游标存在意义:解决"select *"返回空.多行记录问题,但凡select,就可能多行结果集,也就需要用游标. 游标分4步走:cursor.open.fetch.close ...
- PL/SQL游标详解
刚打开游标的时候,是位于一个空行,要用fetch into 才能到第一行. 只是要注意用更新游标的时候,不能在游标期间commit. 否则会报ORA-01002: fetch out of seque ...
- 第12章:MongoDB-CRUD操作--文档--查询--游标详解
①是什么游标 游标不是查询结果,可以理解为数据在遍历过程中的内部指针,其返回的是一个资源,或者说数据读取接口. 客户端通过对游标进行一些设置就能对查询结果进行有效地控制,如可以限制查询得到的结果数量. ...
- SQLServer 存储过程详解
Transact-SQL中的存储过程,非常类似于Java语言中的方法,它可以重复调用.当存储过程执行一次后,可以将语句缓存中,这样下次执行的时候直接使用缓存中的语句.这样就可以提高存储过程的性能. Ø ...
- oracle --游标详解(转)
转自:http://blog.csdn.net/liyong199012/article/details/8948952 游标的概念: 游标是SQL的一个内存工作区,由系统或用户以变量的形式定 ...
随机推荐
- MySql命令——表相关
auto_increment //自动增长 primary key(id) //指定主键 select last_insert_id();//获得添加列的主键值 create table produc ...
- JavaScript --------------继前面继承方式-------总结
创建对象方式: 工厂模式:使用简单的函数创建对象,为对象添加属性和方法,然后返回对象: function createPerson(name,age,job){ var o = new Object( ...
- Cisco cmd 命令(二)
1.配置路由器静态路由选择表 ip route [destination_network] [mask] [next_hop_address or exitinterface] [administra ...
- FOR UPDATE SKIP LOCKED
SYS_UNIT 中有UNIT_ID 0000000001 0000000002 0000001100 原意为若启用多线程,则每个线程在获取时仅可以获取一条数据(互斥) 脚本如下 1.SELECT * ...
- ios学习笔记-数据持久化
沙盒 沙盒是一种数据安全策略,只允许自己的应用访问目录.可以使用NSHomeDirectory()获取. ios沙盒下有三个子目录: 1.Documents目录:用于存储比较大的文件活着需要频发女更新 ...
- 6、Khala的登录生命周期管理
khala能够对设备进行生命周期管理,并提供了与生命周期相关的接口,用户只需在具体的设备类型实现类中重写这些生命周期接口,即可享受khala对于生命周期管理的同时定制与业务相关的操作.具体接口解释如下 ...
- Linux系统的组成和内核的组成
关于linux的组成的宏观认识. 组成图: 内核组成: 一个完整的Linux内核一般由5部分组成,它们分别是内存管理.进程管理.进程间通信.虚拟文件系统和网络接口.
- MySQL 常用字段类型,介绍及其建表使用方法经验分享
由于工作的公司没有专业的DBA又经常需要建立各种各种的表来满足自己的业务逻辑,所以经常查看MySQL 手册或者谷歌查看相关资料,所以本人就根据我的工作经验和相关资料来介绍一下MySQL各种字段类型及其 ...
- 愉快的开始 - 零基础入门学习Python000
愉快的开始 让编程改变世界 Change the world by program 为什么是Python 既然有各种各样的编程语言可以选择,小甲鱼为什么极力鼓励大家来学习Python呢? 跨平台哦亲 ...
- oc语言--内存管理
一.基本原理 1.什么是内存管理 1> 移动设备的内存及其有限,每个app所能占用的内存是有限制的 2> 当app所占用的内存较多时,系统就会发出内存警告,这是需要回收一些不需要的内存空间 ...