SQL游标原理和使用方法

数据库开发过程中,当你检索的数据只是一条记录时,你所编写的事务语句代码往往使用SELECT INSERT 语句。但是我们常常会遇到这样情况,即从某一结果集中逐一地读取一条记录。那么如何解决这种问题呢?游标为我们提供了一种极为优秀的解决方案。
1.1 游标和游标的优点
    在数据库中,游标是一个十分重要的概念。游标提供了一种对从表中检索出的数据进行操作的灵活手段,就本质而言,游标实际上是一种能从包括多条数据记录的结 果集中每次提取一条记录的机制。游标总是与一条T_SQL 选择语句相关联因为游标由结果集(可以是零条、一条或由相关的选择语句检索出的多条记录)和结果集中指向特定记录的游标位置组成。当决定对结果集进行处理 时,必须声明一个指向该结果集的游标。如果曾经用 C 语言写过对文件进行处理的程序,那么游标就像您打开文件所得到的文件句柄一样,只要文件打开成功,该文件句柄就可代表该文件。对于游标而言,其道理是相同 的。可见游标能够实现按与传统程序读取平面文件类似的方式处理来自基础表的结果集,从而把表中数据以平面文件的形式呈现给程序。

    我们知道关系数据库管理系统实质是面向集合的,在MS SQL SERVER 中并没有一种描述表中单一记录的表达形式,除非使用where 子句来限制只有一条记录被选中。因此我们必须借助于游标来进行面向单条记录的数据处理。
    由此可见,游标允许应用程序对查询语句select 返回的行结果集中每一行进行相同或不同的操作,而不是一次对整个结果集进行同一种操作;它还提供对基于游标位置而对表中数据进行删除或更新的能力;而且, 正是游标把作为面向集合的数据库管理系统和面向行的程序设计两者联系起来,使两个数据处理方式能够进行沟通。

1.2 游标种类
MS SQL SERVER 支持三种类型的游标:Transact_SQL 游标,API 服务器游标和客户游标。
(1) Transact_SQL 游标
    Transact_SQL 游标是由DECLARE CURSOR 语法定义、主要用在Transact_SQL 脚本、存储过程和触发器中。Transact_SQL 游标主要用在服务器上,由从客户端发送给服务器的Transact_SQL 语句或是批处理、存储过程、触发器中的Transact_SQL 进行管理。 Transact_SQL 游标不支持提取数据块或多行数据。
(2) API 游标
    API 游标支持在OLE DB, ODBC 以及DB_library 中使用游标函数,主要用在服务器上。每一次客户端应用程序调用API 游标函数,MS SQL SEVER 的OLE DB 提供者、ODBC驱动器或DB_library 的动态链接库(DLL) 都会将这些客户请求传送给服务器以对API游标进行处理。
(3) 客户游标
    客户游标主要是当在客户机上缓存结果集时才使用。在客户游标中,有一个缺省的结果集被用来在客户机上缓存整个结果集。客户游标仅支持静态游标而非动态游 标。由于服务器游标并不支持所有的Transact-SQL 语句或批处理,所以客户游标常常仅被用作服务器游标的辅助。因为在一般情况下,服务器游标能支持绝大多数的游标操作。
    由于API 游标和Transact-SQL 游标使用在服务器端,所以被称为服务器游标,也被称为后台游标,而客户端游标被称为前台游标。在本章中我们主要讲述服务器(后台)游标。

select count(id) from info

select * from info

--清除所有记录
truncate table info

declare @i int
set @i=1
while @i <1000000
begin
insert into info values('Justin'+str(@i),'深圳'+str(@i))
set @i=@i+1
end

1.3 游标操作
使用游标有四种基本的步骤:声明游标、打开游标、提取数据、关闭游标。
声明游标
象使用其它类型的变量一样,使用一个游标之前,首先应当声明它。游标的声明包括两个部分:游标的名称;这个游标所用到的SQL语句。如要声明一个叫作Cus-tomerCursor的游标用以查询地址在北京的客户的姓名、帐号及其余额,您可以编写如下代码:
DECLARE CustomerCursor CURSOR FOR
SELECT acct_no,name,balance
FROM customer
WHERE province="北京";
在游标的声明中有一点值得注意的是,如同其它变量的声明一样,声明游标的这一段代码行是不执行的,您不能将debug时的断点设在这一代码行上,也不能用IF...END IF语句来声明两个同名的游标,如下列的代码就是错误的。
IF Is_prov="北京"THEN
DECLARE CustomerCursor CURSOR FOR
SELECT acct_no,name,balance
FROM customer
WHERE province="北京";
ELSE
DECLARE CustomerCursor CURSOR FOR
SELECT acct_no,name,balance
FROM customer
WHERE province〈〉"北京";
END IF
打开游标
声明了游标后在作其它操作之前,必须打开它。打开游标是执行与其相关的一段SQL语句,例如打开上例声明的一个游标,我们只需键入:
OPEN CustomerCursor;
由于打开游标是对数据库进行一些SQL SELECT的操作,它将耗费一段时间,主要取决于您使用的系统性能和这条语句的复杂程度。如果执行的时间较长,可以考虑将屏幕上显示的鼠标改为hourglass。
提取数据
当用OPEN语句打开了游标并在数据库中执行了查询后,您不能立即利用在查询结果集中的数据。您必须用FETCH语句来取得数据。一条FETCH语句一次 可以将一条记录放入程序员指定的变量中。事实上,FETCH语句是游标使用的核心。在DataWindow和DataStore中,执行了 Retrieve()函数以后,查询的所有结果全部可以得到;而使用游标,我们只能逐条记录地得到查询结果。
已经声明并打开一个游标后,我们就可以将数据放入任意的变量中。在FETCH语句中您可以指定游标的名称和目标变量的名称。如下例:
FETCH CustmerCur-sor
INTO:ls_acct_no,
:ls_name,
:ll_balance;
从语法上讲,上面所述的就是一条合法的取数据的语句,但是一般我们使用游标却还应当包括其它的部分。正如我们前面所谈到的,游标只能一次从后台数据库中取 一条记录,而在多数情况下,我们所想要作的是在数据库中从第一条记录开始提取,一直到结束。所以我们一般要将游标提取数据的语句放在一个循环体内,直至将 结果集中的全部数据提取后,跳出循环圈。通过检测SQLCA.SQL-CODE的值,可以得知最后一条FETCH语句是否成功。一般,当SQLCODE值 为0时表明一切正常,100表示已经取到了结果集的末尾,而其它值均表明操作出了问题,这样我们可以编写以下的代码:
lb_continue=True
ll_total=0
DO WHILE lb_continue
FETCH CustomerCur-sor
INTO:ls_acct_no,
:ls_name,
:ll_balance;
If sqlca.sqlcode=0 Then
ll_total+=ll_balance
Else
lb_continue=False
End If
LOOP
循环体的结构有多种,这里提到的是最常见的一种。也有的程序员喜爱将一条FETCH语句放在循环体的前面,循环体内再放置另外一条FETCH语句,并检测SQLCA.SQLCODE是否为100。但是这样做,维护时需同时修改两条FETCH语句,稍麻烦了些。
关闭游标
在游标操作的最后请不要忘记关闭游标,这是一个好的编程习惯,以使系统释放游标占用的资源。关闭游标的语句很简单:
CLOSE CustomerCursor;
使用Where子句子
我们可以动态地定义游标中的Where子句的参数,例如在本例中我们是直接定义了查询省份是北京的记录,但也许在应用中我们要使用一个下拉式列表框,由用户来选择要查询的省份,我们该怎样做呢?
我们在前面曾经提到过,DECLARE语句的作用只是定义一个游标,在OPEN语句中这个游标才会真正地被执行。了解了这些,我们就可以很方便地实现这样的功能,在DECLARE的Where子句中加入变量作参数,如下所示:
DECLARE CustomerCursor CURSOR FOR
SELCECT acct_no,name,balance
FROM customer
WHERE province=:ls_province;
∥定义ls_province的值
OPEN CustomerCursor;
游标的类型
同其它变量一样,我们也可以定义游标的访问类型:全局、共享、实例或局部,游标变量的命名规范建议也同其它变量一样。
--声明游标
declare my_cursor cursor keyset for select * from info
--删除游标资源
deallocate my_cursor

--打开游标,在游标关闭或删除前都有效
open my_cursor
--关闭游标
close my_cursor

--声明局部变量
declare @id int,@name varchar(20),@address varchar(20)
--定位到指定位置的记录
fetch absolute 56488 from my_cursor into @id,@name,@address
select @id as id,@name as name,@address as address
--定位到当前记录相对位置记录
fetch relative -88 from my_cursor into @id,@name,@address
select @id as id,@name as name,@address as address
--定位到当前记录前一条
fetch prior from my_cursor into @id,@name,@address
select @id as id,@name as name,@address as address
--定位到当前记录后一条
fetch next from my_cursor into @id,@name,@address
select @id as id,@name as name,@address as address
--定位到首记录
fetch first from my_cursor into @id,@name,@address
select @id as id,@name as name,@address as address
--定位到尾记录
fetch last from my_cursor into @id,@name,@address
select @id as id,@name as name,@address as address

实例:
use database1
declare my_cursor cursor scroll dynamic
/**//*scroll表示可随意移动游标指        针(否则只能向前),dynamic表示可以读写游标(否则游标只读)*/
for
select productname from  product

open my_cursor
declare @pname sysname
fetch next from my_cursor into @pname
while(@@fetch_status=0)
  begin
    print 'Product Name: ' + @pname
    fetch next from my_cursor into @pname
  end
fetch first from my_cursor into @pname
print @pname
/**//*update product set productname='zzg' where current of my_cursor */
/**//*delete from product where current of my_cursor */
close my_cursor
deallocate my_cursor


1.4 游标的高级技巧

尽管目前基于SQL语句的后台数据库所支持的语言都大致相当,但对游标的支持却有着一些差异,例如对滚动游标支持。所谓滚动游标,就是程序员可以指定游标 向前后任意一个方向滚动。如在Informix中,您甚至还可以将游标滚向结果集开头或末尾,使用的语句分别是FETCH FIRST,FETCH LAST、FETCH PRIOR和FETCH NEXT。当程序员用FETCH语句,其缺省是指FETCH NEXT。由于滚动是在数据库后台实现的,所以滚动游标为用户编程提供了极大的方便。
对游标支持的另一个不同是可修改游标。上述游标的使用都是指只读游标,而象Oracle、Sybase等数据库却另外支持可作修改的游标。使用这样的数据库,您可以修改或删除当前游标所在的行。例如修改当前游标所在行的用户的余额,我们可以如下操作:
UPDATE customer
SET balance=1000
WHERE CURRENT of customerCursor;
删除当前行的操作如下:
DELETE FROM Customer
WHERE CURRENT OF CustomerCursor;
但是如果您当前使用的数据库是Sybase,您需要修改数据库的参数,将游标可修改的值定为1,才能执行上述操作。这一赋值在连接数据库的前后进行均可。
SQLCA.DBParm="Cursor Update=1"
另外一个内容是动态游标,也就是说您可以运行过程中动态地形成游标的SELECT语句。这同在PowerBuilder中动态地使用嵌入式SQL一样,需要用到DynamicStagin-gArea等数据类型,这已超出了本节的范围。

转载于:https://www.cnblogs.com/yongbin621/archive/2009/03/24/1420270.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/463536.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

varnish-cache使用

Varnish Cache是一个web加速软件&#xff0c;用作web服务加速的反向代理&#xff0c;与Squid不同的是它建立在较新的系统内核调用上&#xff0c;并且主要是使用内存作为缓存&#xff0c;它现有的使用者有facebook等&#xff0c;据使用者反馈&#xff0c;其与Squid相比&#xff…

CF617E XOR and Favorite Number

CF617E XOR and Favorite Number 已知一个序列 \(a_1,\ a_2,\ \cdots,\ a_n\) 和 \(k\) &#xff0c;\(m\) 次询问给出 \(l,\ r\) &#xff0c;求 \(\displaystyle\sum_{il}^r\sum_{ji}^r[a_x\oplus a_{x1}\oplus \cdots \oplus a_yk]\) \(n,\ m\leq10^5,\ 0\leq a_i,\ k\leq10…

2020年文章汇总

据悉&#xff0c;深圳某工程师沦为C语言笔试枪手修改cmdline 把内存改成512MB上拉电阻的作用剖析C语言是如何画出这样的三角形的c语言画谢宾斯基三角形Linux字符设备驱动实例哦&#xff0c;这是桶排序回答一个微信好友的创业问题Linux-C编程 / 多线程 / 如何终止某个线程&#…

不理解Zookeeper一致性原理,谈何异地多活改造

转载&#xff1a;http://developer.51cto.com/art/201805/574334.htm Zookeeper 是最终一致性的&#xff0c;由于多副本&#xff0c;以及保证大多数成功的 Zab 协议&#xff0c;当一个客户端进程写入一个新值&#xff0c;另一个客户端进程不能保证马上就会读到&#xff0c;但能…

作诗一首

只恐花尽老相催&#xff0c;为爱鸬鹚雨里飞。 大珠小珠落玉盘&#xff0c;今日征行何岁归。 今日&#xff0c;在此作诗一首&#xff0c;来抒发一下老周我对心爱的小邢的思念。虽内心迷茫&#xff0c;却仍然坚守&#xff1b;虽征邢之难&#xff0c;偏向邢征行。只为相信曾经——…

一道C#类型转换的思考题

c#中&#xff0c;short s1 1; s1 s1 1;有什么错? &#xff08;真有问题&#xff09;short s1 1; s1 1;有什么错?&#xff08;没问题&#xff09;分析&#xff1a;留给你们。转载于:https://www.cnblogs.com/legecoding/archive/2012/07/23/2604991.html

程序员修炼之道--从小工到专家(一)

这个假期里看了一下这本书&#xff0c;乍一看名字&#xff0c;觉得这就是比较鸡汤类的书吧&#xff0c;但是在看了一部分之后&#xff0c;忽然感觉到&#xff0c;以前的自己真的是很无知&#xff0c;一直就没有认识到做一个真实的项目的困难性&#xff0c;也根本就没有真正的认…

2018年文章汇总

Android ANR 实例分析Linux kernel计算某段代码运行时间Linux Kernel 发展和内核特点C/C函数指针与指针函数(二)老王带你理解算法复杂度O(1),O(N),O(N^2)Android NDK Tombstone/Crash 分析堆和栈的区别&#xff08;转过无数次的文章&#xff09;C语言scanf-周末杂想C语言-scanf…

C++11:右值引用和转移赋值

1、左值与右值的区别&#xff1a; 左值&#xff1a;能别赋值的值&#xff1b;能取到地址的值&#xff0c;用&能取到地址&#xff0c;具有持久性&#xff1b; 右值&#xff1a;临时变量&#xff1b;不能用&取到地址&#xff1b;只是字面常量值 2、右值引用 一般用的…

[备忘]Visual Studio常用小技巧

1. 怎样调整代码排版的格式&#xff1f; 选择&#xff1a;编辑—>高级—>设置文档的格式 或 编辑—>高级—>设置选中代码的格式。 格式化cs代码&#xff1a;Ctrlkf 格式化aspx代码&#xff1a;Ctrlkd 2. 怎样跳转到指定的某一行&#xff1f; 两种方法&#…

Angular CLI的简单使用(1)

参考地址: https://v2.angular.cn/docs/ts/latest/cli-quickstart.html Angular CLI是一个命令行界面工具&#xff0c;它可以创建项目、添加文件以及执行一大堆开发任务&#xff0c;比如测试、打包和发布。 1. 请先在终端/控制台窗口中运行命令 node -v 和 npm -v, 如下图,没有…

在没有数据集的情况下使用数据表

使用数据适配器填充数据表 View Code using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using System.Data.SqlClient;namespace PopDataTable {class Program{static void Main(string[] args){string connString…

2019年文章汇总

要不要去培训机构深造一下&#xff1f;我一个37岁的程序员朋友Linux内核中的GPIO系统整理的免费资料&#xff0c;帮你年后跳槽C语言&#xff0c;字符串指针做函数参数书籍推荐过年回家抢票攻略C语言&#xff0c;函数不可返回指向栈内存的指针你还会写这段C51程序吗&#xff1f;…

一种简单的LRU cache设计 C++

最近在工作中需要用到LRU cache用作缓存来提高性能&#xff0c;经过查阅各种资料&#xff0c;了解了其运行的机制&#xff0c;如下&#xff1a; LRU cache可以用于在内存中保持当前的热点数据&#xff0c;下面实现一个有大小限制的lru cache&#xff0c;相关如下&#xff1a; …

开博了,喜欢这里的气氛

开博了&#xff0c;喜欢这里的气氛 以后经常写东西 学PHP不久&#xff0c;很多东西需要学习 我的站点 www.zhibowang.cn www.xzld.com转载于:https://www.cnblogs.com/gxphp/archive/2009/04/05/1429819.html

bsgs整理

目录 bsgs问题 或 poj2417&#xff1a;概述代码exbsgs鸣谢 \(gzy gzy gzy\)bsgs问题 或 poj2417&#xff1a; 给定质数\(p\)&#xff0c;给定\(a\),\(b\),\((a,p)1\) 求出最小的整数x&#xff0c;使得\(a^{x}≡b(mod p)\) 概述 由费马小定理可以知道\(a^{xp-1}≡a^{x}≡b(mod p…

两个指针变量可以相减

两个指针变量可以相减转载于:https://www.cnblogs.com/LoveFishC/archive/2012/07/23/3845529.html

linux下修改max_user_processes和open_file的最大值

从事分布式服务器开发工作的都会遇到&#xff0c;linux下open_file的值默认是1024&#xff1b;max user processes的值默认是4096&#xff0c;在实际用于中&#xff0c;这两个值严重不足&#xff0c;常常需要调整这两个值。默认配置如下&#xff1a; 可以通过以下两种方式修改&…

Silverlight 全屏显示

privatevoidFullScreenButton_Click(objectsender, RoutedEventArgs e) { Application.Current.Host.Content.IsFullScreen Application.Current.Host.Content.IsFullScreen?false:true; }转载于:https://www.cnblogs.com/star250/archi…

IP SLA的路径控制

一、定义SLA 服务水平协议&#xff08;简称&#xff1a;SLA&#xff0c;全称&#xff1a;service level agreement&#xff09;是在一定开销下为保障服务的性能和可靠性&#xff0c;服务提供商与用户间定义的一种双方认可的协定。通常这个开销是驱动提供服务质量的主要因素。简…