甲乙小朋友的房子

甲乙小朋友很笨,但甲乙小朋友不会放弃

0%

SQL游标

简介

场景

从某一结果集中地逐一读记录 ### 游标本质 能从包括多条数据记录的结果集中每次提取一条记录的机制。

我们知道关系数据库管理系统实质是面向集合的,在MS SQL SERVER 中并没有一种描述表中单一记录的表达形式,除非使用where 子句来限制只有一条记录被选中。因此我们必须借助于游标来进行面向单条记录的数据处理。 ### 游标种类 - Transact_SQL 游标 - API 游标 - 客户游标

游标操作

使用游标有四种基本的步骤:声明游标、打开游标、提取数据、关闭游标。

声明游标

游标的声明包括两个部分:游标的名称 + 这个游标所用到的SQL语句。

例:要声明一个叫作Cus-tomerCursor的游标用以查询地址在北京的客户的姓名、帐号及其余额:

1
2
3
4
DECLARE CustomerCursor CURSOR FOR 
SELECT acct_no,name,balance
FROM customer
WHERE province="北京";

TIPS:

  • 声明游标的这一段代码行是不执行的,不能将debug时的断点设在这一代码行上,也不能用IF语句来声明两个同名的游标,如下列的代码就是错误的。
1
2
3
4
5
6
7
8
9
10
11
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语句

1
OPEN CustomerCursor;

提取数据

必须用FETCH语句来取得数据。

一条FETCH语句一次可以将一条记录放入程序员指定的变量中。

事实上,++FETCH语句是游标使用的核心++。

用游标提取一条数据:

1
2
3
4
FETCH CustmerCur-sor 
INTO:ls_acct_no,
:ls_name,
:ll_balance;

用游标遍历很多条数据:

而在多数情况下,我们所想要作的是在数据库中从第一条记录开始提取,一直到结束。所以我们一般要将游标提取数据的语句放在一个循环体内,直至将结果集中的全部数据提取后,跳出循环圈。

通过检测SQLCA.SQL-CODE的值,可以得知最后一条FETCH语句是否成功。

一般,当SQLCODE值为0时表明一切正常,100表示已经取到了结果集的末尾,而其它值均表明操作出了问题,这样我们可以编写以下的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
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 #如果SQLCA.SQL-CODE==0,则一切正常
ll_total+=ll_balance
Else #跳出循环
lb_continue=False
End If
LOOP

关闭游标

1
CLOSE CustomerCursor;

使用Where子句子

我们可以动态地定义游标中的Where子句的参数,例如在本例中我们是直接定义了查询省份是北京的记录,但也许在应用中我们要使用一个下拉式列表框,由用户来选择要查询的省份,我们该怎样做呢? 我们在前面曾经提到过,DECLARE语句的作用只是定义一个游标,在OPEN语句中这个游标才会真正地被执行。了解了这些,我们就可以很方便地实现这样的功能,在DECLARE的Where子句中加入变量作参数,如下所示:

1
2
3
4
5
6
DECLARE CustomerCursor CURSOR FOR 
SELCECT acct_no,name,balance
FROM customer
WHERE province=:ls_province;
∥定义ls_province的值
OPEN CustomerCursor;

游标的类型

同其它变量一样,我们也可以定义游标的访问类型:全局、共享、实例或局部,游标变量的命名规范建议也同其它变量一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
--声明游标
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

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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