刚刚接到一个面试电话,对头的先生问我懂不懂触发器和存储过程,当时是觉得有些好笑,毕竟“视图、触发和存储”是咱数据库工程师的吉祥三宝,怎么可能不认识?只是稍后他还问了下游标这东西,仔细想想我是不常使用Cursor,因为大表用上游标来遍历会降低查询效率,一般都是推荐面向集合的方式来解决问题而非遍历。不过既然有游标这东西,必定有它存在的价值,不妨就来扒皮下游标~

有玩过asp这种过时语言的朋友应该很能理解游标是啥东西,其实就是一个指针指着数据集里的某一行,然后像asp中用dataset.NEXT()或者dataset.PRE()的代码(希望没写错,我不写asp很久了)让这个指针指向下一行或者上一行的数据。于是这个游标呀,从头指到尾,就完成一次遍历。一般来说特大的表就别玩游标了,尽量用面向集合、面向整体的途径来解决问题,毕竟游标是“读一行、处理一行、指向下一行。。。”,而后者是“一口气把需要操作的行全读出来然后一口气处理完”。

不过有时候写存储过程,涉及的又是小规模的表,那么游标也是挺有用的,也不唠嗑太多,下面讲游标(Cursor)的用法。

先说说游标的定义,其实很简单,跟我们定义一个变量一样:

DECLARE @youbiao CURSOR

那么赋值呢?的确跟常规变量赋值一样用SET,不过等号右方存在格式上的不同:

DECLARE @youbiao CURSOR
--赋值,等号右边要加CURSOR FOR select_command
SET @youbiao = CURSOR FOR
select * from table_name

当然上述的是游标变量的定义和赋值,而常规类型的游标定义与赋值如下:

DECLARE youbiao2 CURSOR
FOR
select * from table_name

好了,现在利用游标来实现下最简单的功能,比如我下面有这张叫series的很简单的表:

我想建个游标让它指向第二行,然后打印(PRINT)出该行的name(也就是“岭南艺术团”)出来。代码如下:

DECLARE youbiao CURSOR
FOR
select name from series OPEN youbiao
DECLARE @name NVARCHAR(20)
FETCH NEXT FROM youbiao INTO @name
FETCH NEXT FROM youbiao INTO @name
PRINT @name CLOSE youbiao
DEALLOCATE youbiao

如上我在“select name from series”的查询结果上建立了一个名为“youbiao”的游标,接着用OPEN youbiao打开此游标来使用其功能;

@name这个变量是用来存放我们从游标里获得的当行name字段的数据,接着后面的语句

FETCH NEXT FROM youbiao INTO @name

表示游标开始指向第一行,在这里要记住 FETCH NEXT FROM 游标名 INTO 变量名 的格式。

由于现在游标是指向首行,而我们想要第二行的数据,那么我们再写一句 FETCH NEXT FROM youbiao INTO @name 让游标指向第二行即可,然后打印出该行name字段的数据。

最后的CLOSE 和 DEALLOCATE 都是关闭、释放游标的关键字(其实只要用DEALLOCATE即可彻底销毁游标了,CLOSE只是暂时关闭,你可以用OPEN重新打开),这跟我们ADO.NET里con用完就con.close()掉一样是个必要的好习惯。

前面说过游标是拿来遍历的,如果一张表很多行,我们也不至于要写一堆“FETCH NEXT FROM XX INTO @XX”来让执行吧。当然不用,游标一般使用WHILE和@@FETCH_STATUS来遍历表,其中的@@FETCH_STATUS是一个全局变量,记住就行(你输入@@F的时候会有智能提示的,直接选就得了),代码如下:

DECLARE @id INT
DECLARE @name NVARCHAR(20)
DECLARE youbiao2 CURSOR
FOR
SELECT id,NAMe FROM series
OPEN youbiao2
FETCH NEXT FROM youbiao2 INTO @id,@name
WHILE ( @@FETCH_STATUS = 0 )
BEGIN
PRINT @id
PRINT @name
FETCH NEXT FROM youbiao2 INTO @id,@name END
CLOSE youbiao2
DEALLOCATE youbiao2

执行结果:

@@FETCH_STATUS是用于判断游标指针位置的全局变量,且 @@FETCH_STATUS默认值为0。其值和对应的意义如下:

  值   意义
0 FETCH 语句成功
-1   语句失败或此行不在结果集中  
-2 被提取的行不存在

  

@@fetch_status值的改变是通过fetch next from实现的,若游标已在最后一行无法再FETCH NEXT了,则@@fetch_status的值会由0变为-1。

这里有个SQL的bug要说一下,尽量把第一条FETCH语句写在OPEN cursor_name的下一行,例如,若把OPEN写在WHILE外部而第一条FETCH语句写在WHILE内部可能会引起代码仅可成功执行一次的问题(再执行就只显示“命令已成功完成”的信息)。

好了,上面我们介绍了FETCH NEXT,下面来介绍下FETCH FIRST/LAST/PRIOR/ABSOLUTE n/RELATIVE n

FIRST/LAST/PRIOR 这三个很好理解,分别是指向第一行/最后一行/前一行,比如“FETCH PRIOR FROM youbiao2 INTO @id,@name”就是让游标youbiao2指向上一行的数据,这里就不赘述了。

对于后俩个“ABSOLUTE n”和“RELATIVE n”,搞前端的同学估计乐了,咱CSS的position也有absolute和relative可选呢~ 其实这儿也一样是“绝对”和“相对”的意思,其中ABSOLUTE n表示跳到第n行去,而RELATIVE n示跳到相对于当前行的第n行去,如:

注意代码中红圈处,我加了个参数SCROLL,这是因为若要动用到“ABSOLUTE n”和“RELATIVE n”等NEXT之外的选项,就必须加此SCROLL参数,表明允许游标往任意方向游走。如果不加SCROLL则默认为FORWARD_ONLY,表示只允许游标从头到尾游动。

下面借用其他前辈们的介绍文段来简略谈下游标更多的参数,这些前面没提到的参数用的比较少。

我们还是先看看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二选一
LOCAL意味着游标的生存周期只在批处理或函数或存储过程中可见,而GLOBAL意味着游标对于特定连接作为上下文,全局内有效。如果不指定游标作用域,默认作用域为GLOBAL。

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不锁定任何数据,当需要在游标中更新数据时,如果底层表数据更新,则游标内数据更新不成功,如果,底层表数据未更新,则游标内表数据可以更新

游标其实也是一简单的东西,配合上FETCH ABSOLUTE n/RELATIVE n 神马的也能灵活地执行我们想要的操作,不过依旧如开头所说的,不到万不得已的情况还是别用游标好,这东西就跟索引在更新的时候一样,如果把一个特大的表循环遍历一遍,那真会是个伤心的故事。

来科普下游标(MSSQL)这东西。。。的更多相关文章

  1. 同步OR异步?WebFlux开发真的比Servlet开发要快?顺便再科普下CompletableFuture

    在看下文之前,先给大家科普一点基础知识 Runable:线程任务类接口,没有返回值 Callable:与上面的不同就是有返回值 Executor:定义了线程池执行任务的接口,不过只定义了Runable ...

  2. 简单科普下hosts文件原理与制作

    简单科普下hosts文件原理与制作 hosts文件是一个用于储存计算机网络中各节点信息的计算机文件.这个文件负责将主机名映射到相应的IP地址.hosts文件通常用于补充或取代网络中DNS的功能.和DN ...

  3. Linux环境下连接Mssql 2008

    首先,Linux环境装个驱动:Microsoft® SQL Server® ODBC Driver 1.0 for Linuxhttps://www.microsoft.com/en-us/downl ...

  4. Linux下连接MSSQL之安装FreeTDS

    $ tsql -H MSSQL服务器服务IP -p 1433 -U MSSQL服务器登陆帐号 -P MSSQL服务器登陆密码http://www.cnblogs.com/ilovexiao/p/355 ...

  5. G++ 4.4.7 无法编译模板程序,Vs可以,和解?智者尾部留言,本人第一次使用vs pro,通常并且习惯在linux下写些小东西,虽然程序简单;

    vs 模板编译运行Ok \ linux g++ 4.4.7编译模板测试程序,报无法定义 template <typename or class 中的 AnyType> 类型的数据 Exam ...

  6. 简单探究一下window下的wifi各种东西

    保存地方在哪里 C:\ProgramData\Microsoft\Wlansvc\Profiles\Interfaces HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\W ...

  7. php5.4window下连接mssql

    第一步 下载 http://www.microsoft.com/en-us/download/details.aspx?id=20098 [PHP_PDO_SQLSRV] extension=php_ ...

  8. 走向DBA[MSSQL篇] 详解游标

    原文:走向DBA[MSSQL篇] 详解游标 前篇回顾:上一篇虫子介绍了一些不常用的数据过滤方式,本篇详细介绍下游标. 概念 简单点说游标的作用就是存储一个结果集,并根据语法将这个结果集的数据逐条处理. ...

  9. HTTPS科普扫盲帖

    为什么需要https HTTP是明文传输的,也就意味着,介于发送端.接收端中间的任意节点都可以知道你们传输的内容是什么.这些节点可能是路由器.代理等. 举个最常见的例子,用户登陆.用户输入账号,密码, ...

随机推荐

  1. Ceph剖析:数据分布之CRUSH算法与一致性Hash

    作者:吴香伟 发表于 2014/09/05 版权声明:可以任意转载,转载时务必以超链接形式标明文章原始出处和作者信息以及版权声明 数据分布是分布式存储系统的一个重要部分,数据分布算法至少要考虑以下三个 ...

  2. 长轮询(long polling)

    HTTP请求不是持续的连接,你请求一次,服务器响应一次,然后就完了.长轮训是一种利用HTTP模拟持续连接的技巧.具体来说,只要页面载入了,不管你需不需要服务器给你响应信息,你都会给服务器发一个Ajax ...

  3. C#之方法的重载与递归

    (1). 方法的重载:方法的名称相同,但参数不同. 1.如果参数的个数相同,那么参数的类型不能相同. 2.如果参数的类型相同,那么参数的个数不能相同. (2).方法的递归:方法自己调用自己.用于找出一 ...

  4. ASP.NET MVC分页组件MvcPager 2.0版发布暨网站全新改版

    MvcPager分页控件是在ASP.NET MVC Web应用程序中实现分页功能的一系列扩展方法,该分页控件的最初的实现方法借鉴了网上流行的部分源代码, 尤其是ScottGu的PagedList< ...

  5. win7/win8远程桌面 server 2003 卡的问题

    原因在于从vista开始,微软在TCP/IP协议栈里新加了一个叫做“Window Auto-Tuning”的功能.这个功能本身的目的是为了让操作系统根据网络的实时性能(比如响应时间)来动态调整网络上传 ...

  6. 安卓奇葩问题之SQLite条件查找不到数据

    今天真是日了狗了. 先说需求:要做一个累死支付宝首页的可自定义的栏目.栏目是动态从后台获取的,所以就会有一个本地数据和后台数据的同步问题.为了方便对本地数据的增删改查,首先想到SQLite. 然后就写 ...

  7. CentOS 访问Windows7共享文件夹

    在终端中输入命令mount -t cifs -o username="xxx",password="****" //192.168.1.1/share_fold ...

  8. android开发中在界面上实现曲线图的几个开源项目

    转自:https://wapiknow.baidu.com/question/1959128379041474620?qq-pf-to=pcqq.c2c 几个相关开源项目: 1.  MPAndroid ...

  9. 关于selenium截图

    没时间深入研究源代码,凭调试解决了非浏览器级别的滚动条截图. 首先,定位到带有滚动条的元素,通过xpath. 其次,获取scrollheight和clientheight. 第三,循环截图,循环截图的 ...

  10. testng参数化(提供测试数据)【转】

    testng提供测试数据的两个注释:@DataProvide和@Parameter   一.通过testng.xml中设置参数 (实际上testng.xml只是一个名字,可以起任何一个名字,只要是.x ...