走向DBA[MSSQL篇] 详解游标
前篇回顾:上一篇虫子介绍了一些不常用的数据过滤方式,本篇详细介绍下游标。
概念
简单点说游标的作用就是存储一个结果集,并根据语法将这个结果集的数据逐条处理。
观点
正因为游标可以将结果集一条条取出处理,所以会增加服务器的负担。再者使用游标的效率远远没有使用默认的结果集效率高,在默认结果集中,从客户端发送到服务器的唯一一个数据包是包含需执行语句的数据包。而在使用服务器游标时,每一个FETCH语句都必须从客户端发送到服务器,然后在服务器中将它解析并编译为执行计划。除非要再sqlserver上进行很复杂的数据操作。
基本知识
一. SQL Server 2005 支持两种请求游标的方法
1.Transact-SQL (支持 SQL-92);
2.数据库应用程序编程接口(API)游标函数(ADO、OLE DB、ODBC)应用程序不能混合使用这两种请求游标的方法。ODBC 还支持客户端游标,即在客户 端实现的游标。
二. 游标根据范围可以分成全局游标和局部游标。全局游标可以在整个会话过程中使用,局部游标只能在一个T-SQL批、存储过程或触发器中执行,当执行完毕后局部游标会自动删除。
三. 游标的基本操作,定义游标、打开游标、循环读取游标、关闭游标和删除游标。
语法基础(SQL-92)
以SQL-92方式为例
初始数据PPS_App_Infomation
DECLARE @Parm01 varchar(100)
DECLARE @Parm02 varchar(100)
DECLARE @Parm03 varchar(100)
DECLARE cur_Pay INSENSITIVE CURSOR FOR
SELECT GameName,CreateUser,CreateDate FROM [PicPromotion].[dbo].[PPS_App_Infomation]
OPEN cur_Pay
FETCH cur_Pay INTO @Parm01 , @Parm02 , @Parm03
WHILE @@FETCH_STATUS = 0
BEGIN
WAITFOR DELAY '00:00:01'
PRINT @Parm01+'__'+@Parm02+'__'+@Parm03
FETCH cur_Pay INTO @Parm01 , @Parm02 , @Parm03
END
DEALLOCATE cur_Pay
其中 cur_Pay为游标名称 INSENSITIVE 用于设置游标是否使用副本 OPEN 打开游标 fetch循环读入游标 DEALLOCATE 删除游标
INSENSITIVE
举个简单的例子 在游标读取过程中 我们将熬夜虫子改成早起虫子看看 是否添加INSENSITIVE 会是什么样的区别
前一个有INSENSITIVE 关键字使用数据副本,后一个无INSENSITIVE 是即时数据
游标的敏感性行为定义了对基行(用于建立游标)所做的更新是否对游标可见。敏感性也定义了能否通过游标进行更新。
scroll
我们再来看看scroll关键字
DECLARE @Parm01 varchar(100)
DECLARE @Parm02 varchar(100)
DECLARE @Parm03 varchar(100)
DECLARE cur_Pay INSENSITIVE SCROLL CURSOR FOR
SELECT GameName,CreateUser,CreateDate FROM [PicPromotion].[dbo].[PPS_App_Infomation]
OPEN cur_Pay
BEGIN
FETCH LAST FROM cur_Pay INTO @Parm01 , @Parm02 , @Parm03
PRINT @Parm01+'__'+@Parm02+'__'+@Parm03
END
DEALLOCATE cur_Pay
上面的程序是ok的 成功输出 熬夜虫子__Maoya__06 20 2009 1:32PM
如果去掉SCROLL关键字会提示
消息 16911,级别 16,状态 1,第 8 行
fetch: 提取类型 last 不能与只进游标一起使用。
SCROLL通过Transact-SQL服务器游标检索特定行。如果SCROLL 选项未在SQL-92样式的DECLARE CURSOR语句中指定,则NEXT是唯一受支持的FETCH 选项。如果在SQL-92样式的DECLARE CURSOR语句中指定了SCROLL 选项,则支持所有FETCH 选项。
FETCH 语法
除了last参数(返回游标中的最后一行并将其作为当前行)再介绍下其他的
NEXT 紧跟当前行返回结果行,并且当前行递增为返回行。如果FETCH NEXT为对游标的第一次提取操作,则返回结果集中的第一行NEXT为默认的游标提取选项。
PRIOR 返回紧邻当前行前面的结果行,并且当前行递减为返回行。如果 FETCH PRIOR 为对游标的第一次提取操作,则没有行返回并且游标置于第一行之前。
FIRST 返回游标中的第一行并将其作为当前行。
ABSOLUTE { n | @nvar}
如果 n 或 @nvar 为正数,则返回从游标头开始的第 n 行,并将返回行变成新的当前行。如果 n 或 @nvar 为负数,则返回从游标末尾开始的第 n 行,并将返回行变成新的当前行。如果 n 或 @nvar 为 0,则不返回行。n 必须是整数常量,并且 @nvar 的数据类型必须为 smallint、tinyint 或 int。
RELATIVE { n | @nvar}
如果 n 或 @nvar 为正数,则返回从当前行开始的第 n 行,并将返回行变成新的当前行。如果 n 或 @nvar 为负数,则返回当前行之前第 n 行,并将返回行变成新的当前行。如果 n 或 @nvar 为 0,则返回当前行。在对游标完成第一次提取时,如果在将 n 或 @nvar 设置为负数或 0 的情况下指定 FETCH RELATIVE,则不返回行。n 必须是整数常量,@nvar 的数据类型必须为 smallint、tinyint 或 int。
定义全局游标
FETCH NEXT FROM GLOBAL cur_Pay INTO @Parm01 , @Parm02 , @Parm03
如果未指定 GLOBAL,则指局部游标。
READ ONLY 与 UPDATE
(下文中只摘要不重复或者必要的代码)
DECLARE cur_Pay INSENSITIVE SCROLL CURSOR FOR
SELECT GameName,CreateUser,CreateDate FROM [PicPromotion].[dbo].[PPS_App_Infomation]
FOR READ ONLY
OPEN cur_Pay
BEGIN FETCH LAST FROM cur_Pay INTO @Parm01 , @Parm02 , @Parm03
UPDATE PPS_App_Infomation SET GameName ='熬夜虫子forupdate' WHERE CURRENT OF cur_Pay
PRINT @Parm01+'__'+@Parm02+'__'+@Parm03
END
消息 16929,级别 16,状态 1,第 9 行
游标是只读的。
语句已终止。熬夜虫子__Maoya__06 20 2009 1:32PM
DECLARE cur_Pay INSENSITIVE SCROLL CURSOR FOR
SELECT GameName,CreateUser,CreateDate FROM [PicPromotion].[dbo].[PPS_App_Infomation]
FOR UPDATE
消息 1048,级别 15,状态 1,第 7 行
游标选项 FOR UPDATE 和 INSENSITIVE 冲突。
DECLARE cur_Pay SCROLL CURSOR FOR
SELECT GameName,CreateUser,CreateDate FROM [PicPromotion].[dbo].[PPS_App_Infomation]
FOR Update
OPEN cur_Pay
BEGIN
FETCH LAST FROM cur_Pay INTO @Parm01 , @Parm02 , @Parm03
UPDATE PPS_App_Infomation SET GameName ='熬夜虫子forupdate' WHERE CURRENT OF cur_Pay
FETCH LAST FROM cur_Pay INTO @Parm01 , @Parm02 , @Parm03
PRINT @Parm01+'__'+@Parm02+'__'+@Parm03
END
(1 行受影响)
熬夜虫子forupdate__Maoya__06 20 2009 1:32PM
READ ONLY不允许通过游标进行定位更新,并且不持有针对组成结果集的行的锁。UPDATE与READ ONLY相对,并且UPDATE可以定义到可更新的列。
语法基础(SQL SERVER扩展格式)
基础数据同上
DECLARE @Parm01 varchar(100)
DECLARE @Parm02 varchar(100)
DECLARE @Parm03 varchar(100)
DECLARE cur_Pay CURSOR
GLOBAL --和SQL-92格式同理 可选LOCAL本地游标
SCROLL --可选FORWARD_ONLY 指定游标只能从第一行滚动到最后一行
DYNAMIC --和上一行参数关联 static表示临时副本 DYNAMIC直接反映在滚动游标时对结果集内行所做的修改
--keyset表示除了唯一键其他都获取最新值 FAST_FORWARD性能优化的FOR_WARD READONLY游标
OPTIMISTIC --可选READ_ONLY同上 SCROLL_LOCKS定位更新并对当前数据加锁 OPTIMISTIC想当与乐观锁可以进行更新动作但是如果读取的数据被更新会导致操作失败
TYPE_WARNING --如果游标从所请求的类型隐形转换到另一种类型,则给客户端发送警告
FOR
SELECT GameName,CreateUser,CreateDate FROM [PicPromotion].[dbo].[PPS_App_Infomation]
FOR UPDATE
OPEN cur_Pay
BEGIN
FETCH LAST FROM cur_Pay INTO @Parm01 , @Parm02 , @Parm03
PRINT @Parm01+'__'+@Parm02+'__'+@Parm03
END
DEALLOCATE cur_Pay
相关语法都直接注释在code里了 和SQL-92相似的部分就不赘述了
游标应用
定义游标变量cursor_variable_name
declare @tcur cursor
set @tcur = cursor for SELECT * FROM PPS_App_Infomation
打开游标 OPEN {{[GLOBAL]cursor_name}|cursor_variable_name}
关闭游标 CLOSE{{[GLOBAL]cursor_name}|cursor_variable_name}
释放游标 DEALLOCATE{{[GLOBAL]cursor_name}|cursor_variable_name}
获取游标行数 @@CURSOR_ROWS
DECLARE cur_Pay INSENSITIVE SCROLL CURSOR FOR
SELECT GameName,CreateUser,CreateDate FROM [PicPromotion].[dbo].[PPS_App_Infomation]
OPEN cur_Pay
BEGIN
PRINT @@CURSOR_ROWS
END
输出
检测fetch操作的状态@@FETCH_STATUS 返回值0表示fetch语句执行成功 -1表示fetch语句执行失败或此行不再结果集中 -2表示所要读取的数据信息不存在
DECLARE cur_Pay INSENSITIVE SCROLL CURSOR FOR
SELECT GameName,CreateUser,CreateDate FROM [PicPromotion].[dbo].[PPS_App_Infomation]
FETCH next FROM cur_Pay
OPEN cur_Pay
BEGIN
if(@@FETCH_STATUS = 0) print('FETCH 语句成功')
if(@@FETCH_STATUS = -1) print('FETCH 语句失败或行不在结果集中')
if(@@FETCH_STATUS = -2) print('提取的行不存在')
END
消息 16917,级别 16,状态 2,第 6 行
游标未打开。
FETCH 语句失败或行不在结果集中
游标嵌套
在游标中使用另一个游标。一般来说使用游标已经很占用系统资源了,再嵌套游标会大影响效率,本文只作参考用。
添加一张数据表PPS_AppConfig_Infomation
DECLARE @Parm01 int
DECLARE @Parm02 varchar(100)
DECLARE @Parm03 varchar(100)
DECLARE @Parm04 varchar(100)
DECLARE cur_Pay INSENSITIVE SCROLL CURSOR FOR
SELECT AppId,GameName,CreateUser,CreateDate FROM PPS_App_Infomation
OPEN cur_Pay
BEGIN
FETCH next FROM cur_Pay INTO @Parm01 , @Parm02 , @Parm03 ,@Parm04
WHILE(@@FETCH_STATUS =0)
BEGIN
PRINT('当前游戏编号'+cast(@Parm01 as varchar(4)) +' 游戏名称为'+@Parm02)
DECLARE sub_cur CURSOR FOR
SELECT WM_Type,WM_Text FROM PPS_AppConfig_Infomation WHERE AppId = @Parm01
DECLARE @Parm05 varchar(100)
DECLARE @Parm06 varchar(100)
OPEN sub_cur
FETCH next FROM sub_cur INTO @Parm05 , @Parm06
WHILE(@@FETCH_STATUS =0)
BEGIN
PRINT('当前游戏类型'+@Parm05+'默认软文为'+@Parm06)
FETCH next FROM sub_cur INTO @Parm05 , @Parm06
END
CLOSE sub_cur
DEALLOCATE sub_cur
FETCH next FROM cur_Pay INTO @Parm01 , @Parm02 , @Parm03 ,@Parm04
END END DEALLOCATE cur_Pay
输出结果为
游标关联的系统存储过程
sp_cursor_list 报告当前为连接打开的服务器游标的属性。
DECLARE cur_Pay INSENSITIVE SCROLL CURSOR FOR
SELECT AppId,GameName,CreateUser,CreateDate FROM PPS_App_Infomation
OPEN cur_Pay
DECLARE @REPORT CURSOR
BEGIN
FETCH next FROM cur_Pay
WHILE(@@FETCH_STATUS =0)
BEGIN
FETCH next FROM cur_Pay
END
exec sp_cursor_list @cursor_return = @REPORT output,@cursor_scope =3 --设置1时报告所有本地游标 设置2时报告所有全局游标 设置3时报告所有本地游标和全局游标
END
CLOSE cur_Pay
DEALLOCATE cur_Pay
sp_describe_cursor查看游标的全局特性 作用和sp_cursor_list差不多。
DECLARE cur_Pay INSENSITIVE SCROLL CURSOR FOR
SELECT GameName,CreateUser,CreateDate FROM PPS_App_Infomation
OPEN cur_Pay
DECLARE @REPORT CURSOR
BEGIN
FETCH next FROM cur_Pay
WHILE(@@FETCH_STATUS =0)
BEGIN
FETCH next FROM cur_Pay
END
exec sp_describe_cursor @cursor_return = @REPORT output,@cursor_source =N'globle',@cur_identity=N'cur_Pay'
--@cursor_source 可选N'local',N'globle',N'variable' 选择本地、全局还是变量
--@cur_identity 查看的游标名称
END
CLOSE cur_Pay
DEALLOCATE cur_Pay
关系数据库中的操作会对整个行集起作用。由 SELECT 语句返回的行集包括满足该语句的 WHERE 子句中条件的所有行。这种由语句返回的完整行集称为结果集。应用程序,特别是交互式联机应用程序,并不总能将整个结果集作为一个单元来有效地处理。这些应用程序需要一种机制以便每次处理一行或一部分行。游标就是提供这种机制的对结果集的一种扩展。
走向DBA[MSSQL篇] 详解游标的更多相关文章
- 走向DBA[MSSQL篇] 针对大表 设计高效的存储过程【原理篇】 附最差性能sql语句进化过程客串
原文:走向DBA[MSSQL篇] 针对大表 设计高效的存储过程[原理篇] 附最差性能sql语句进化过程客串 测试的结果在此处 本篇详解一下原理 设计背景 由于历史原因,线上库环境数据量及其庞大,很多千 ...
- 走向DBA[MSSQL篇] 积跬步行千里
原文:走向DBA[MSSQL篇] 积跬步行千里 不知道大家对SQL系列的感不感兴趣 先在这里探个路 本文针对的读者为SQL菜鸟 欢迎大牛驳论或者补充 既然是探路篇 就先说下数据过滤中的偏门匹配 希望能 ...
- 走向DBA[MSSQL篇] 从SQL语句的角度 提高数据库的访问性能
原文:走向DBA[MSSQL篇] 从SQL语句的角度 提高数据库的访问性能 最近公司来一个非常虎的dba 10几年的经验 这里就称之为蔡老师吧 在征得我们蔡老同意的前提下 我们来分享一下蔡老给我们 ...
- 走向DBA[MSSQL篇] 面试官最喜欢的问题 ----索引+C#面试题客串
原文:走向DBA[MSSQL篇] 面试官最喜欢的问题 ----索引+C#面试题客串 对大量数据进行查询时,可以应用到索引技术.索引是一种特殊类型的数据库对象,它保存着数据表中一列或者多列的排序结果,有 ...
- 走向DBA[MSSQL篇] - 从SQL语句的角度提高数据库的访问性能(转)
最近公司来一个非常虎的DBA,10几年的经验,这里就称之为蔡老师吧,在征得我们蔡老同意的前提下 ,我们来分享一下蔡老给我们带来的宝贵财富,欢迎其他的DBA来拍砖. 目录 1.什么是执行计划?执行计划 ...
- PHP函数篇详解十进制、二进制、八进制和十六进制转换函数说明
PHP函数篇详解十进制.二进制.八进制和十六进制转换函数说明 作者: 字体:[增加 减小] 类型:转载 中文字符编码研究系列第一期,PHP函数篇详解十进制.二进制.八进制和十六进制互相转换函数说明 ...
- Scala进阶之路-Scala函数篇详解
Scala进阶之路-Scala函数篇详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传值调用和传名调用 /* @author :yinzhengjie Blog:http: ...
- SQL Server DBA工作内容详解
在Microsoft SQL Server 2008系统中,数据库管理员(Database Administration,简称为DBA)是最重要的角色.DBA的工作目标就是确保Microsoft SQ ...
- CentOS 7 下编译安装lnmp之PHP篇详解
一.安装环境 宿主机=> win7,虚拟机 centos => 系统版本:centos-release-7-5.1804.el7.centos.x86_64 二.PHP下载 官网 http ...
随机推荐
- [Django]models定义choices 字典中的页面显示值
问题: 在django的models.py 在.我们定义一些choices元组,类别似一些字典值.通常下拉框或单个复选框,例如 0相应的M 1妇女和其他有关 class Area(models.Mod ...
- python关于for循环的几个函数
1.enumerate:返回2个值,1是当前的for循环的第几轮,2是循环得到的数值 enumerate works by supplying a corresponding index to eac ...
- oracle迁移mysql数据库注意(转)
oracle转mysql修改: 1. substr() substr( string , 0, 10) 这里测试 必须从 第一位获取 既是 substr(string , 1 , 10)2. to_c ...
- 小米2S TWRP 3.0.2-0 最新版Recovery
主界面 使用了我最新修改的内核 下载地址: 链接: http://pan.baidu.com/s/1i5xwddb 密码: 7dyb 验证信息: md5sum: dca410f33020eb87986 ...
- 基础知识(1)- Java程序设计概述
1.1 Java程序设计平台 1.2 Java“白皮书”的关键术语 1.2.1 简单性 1.2.2 面向对象 1.2.3 网络技能 1.2.4 健壮性 1.2.5 安全性 1.2.6 体系 ...
- [思考] hdu 4811 Ball
意甲冠军: 有三种颜色的小珠,每种颜色的量R,Y,B 转球进入桌面成序,有多少种不同的颜色分别砍下的球在球门前+有多少身后球不同的颜色 问:最大的总比分值 思考: 球和后面的球先放好.剩下的就放中间了 ...
- CentOS 安装apache 及所需的 apr,apr-util,pcre
安装apache前确定已安装 apr,apr-util,pcre 一.安装apr [root@xt test]# tar -zxf apr-1.4.5.tar.gz [root@xt test]# c ...
- Facebook Hacker Cup 2015 Round 1--Corporate Gifting(树动态规划)
原标题:https://www.facebook.com/hackercup/problems.php?pid=759650454070547&round=344496159068801 题意 ...
- 机械革命X5(MECHREVO MR-X5)开包检验
不废话.直接的问题,左右X5没有更具体的信息.为了通过有机会了解后续的选择,具体的数据被释放约: 首先看包装: 1.快递包裹,基于卖方这可以是不同的,包装各不相同 watermark/2/text/a ...
- [C/C++]_[VS2010来源与UTF8中国字符串转码ANSI问题]
现场: 1.思想vs设置源文件UTF8编码,代码中国串出现在它必须是utf8编码,不幸的是,,假定源代码将出现在中国字符串,在存储器中转码ANSI编码. Unicode(UTF8签名) 代码页(650 ...