PRO*C 函数事例 3 -- 游标使用
1、Oracle中的游标
Oracle使用两种游标: 显式游标和隐式游标. 不管语句返回多少条记录, Oracle为每条使用的SQL语句隐式地定义一个游标. Oracle为每个DELETE ,
UPDATE, INSERT 等SQL命令隐式地声明游标. 用户声明并使用显式游标处理SELECT语句返回的多条记录.
游标是ORACLE和PRO*C存放查询结果的工作区域。一个游标(已命名的)与一条SELECT语句相关联。操作游标有由4条命令:
(1)DECLARE CURSOR;(2)OPEN CURSOR;(3)FETCH;(4)CLOSE CURSOR。
A. 定义游标
一个游标必须首先定义, 才能使用它。语法为:
EXEC SQL DECLARE 〈游标名〉CORSOR FOR
SELECT 〈列〉
FROM 〈表〉
例如:
EXEC SQL DECLARE CSOR, CURSOR FOR
SELECT ENAME , JOB, SAL
FROM EMP
WHERE DEPTNO=:DEPTNO;
当赋给一个与查询相关联的游标CURSOR之后, 当SELECT查询EMP时可从
数据库中返回多行,这些行就是CURSOR的一个活动区域。
注意:
1) 定义游标必须在对游标操作之前完成;
2) PRO*C不能引用没有定义的游标;
3) 游标定义后,其作用范围是整个程序。所以对一个程序来讲, 同时定义两个相同的游标是错误的。
B. 申请游标
在定义游标之后, 应用程序在使用游标变量之前, 必须首先调用ALLOCATE语句
申请游标, 也就是为游标变量分配内存区域, ALLOCATE 语法格式为:
EXEC SQL ALLOCATE :cursor_variable;
C. 打开游标
打开游标的OPEN语句主要用来输入主变量的内容,这些主要是WHERE中使用
的主变量。打开游标的语句是:EXEC SQL OPEN 〈游标名〉
当打开游标后,可以从相关的查询中取出多于一行的结果。所有满足查询标准的
行组成一集合,叫做“游标活动集”。通过取操作,活动集中的每一行或每一组是一
个一个返回的,查询完成后, 游标就可关闭了。如图所示:
注意:1)游标处于活动集的第一行前面;
2)若改变了输入主变量就必须重新打开游标。
D. 取数据
从活动集中取出一行或一组把结果送到输出主变量中的过程叫取数据。输出主变量
的定义在取数据语句中。取数据的语句如下:
EXEC SQL FETCH〈游标名〉INTO:主变量1,主变量2,……
FETCH的工作过程如图所示:
如图所示的查询结果指满足查询条件的查询结果。使用FETCH应注意以下几点:
<1> 游标必须先定义再打开。
<2> 只有在游标打开之后才能取数据,即执行FETCH语句。
<3> FETCH语句每执行一次,从当前行或当前组取数据一次,下一行或下一组向上移一次。游标每次所指的行或组都为当前行或当前组,而FETCH
每次都是取游标所指定的行或组的数据。
<4> 当游标活动集空之后,ORCLE返回一个SQLCA。SQLCA(=1403)。
<5> 若希望此游标再操作, 必须先关闭再打开它。
<6> 在C程序中可以开辟一个内存空间,来存放操作结果,这样就能利用开辟的空间来灵活操纵查询的结果。
E.关闭游标
取完活动集中所有行后,必须关闭游标,以释放与该游标有关的资源。
关闭游标的格式为:
EXEC SQL CLOSE 游标名;
例如:
EXEC SQL CLOSE C1;
ORACLE V5.0版支持SQL格式“CURRENT OF CURSOR”。这条语句将指向一个
游标中最新取出的行, 以用于修改和删除操作。该语句必须有取操作之后使用,
它等同存储一个ROWID,并使用它。
F. 释放游标
CLOSE语句在关闭游标变量时, 并未释放游标变量所点用的内存. 所以, 以游标变
量关闭之后应用程序可以重新打开游标变量, 实现各种游标操作. 需要关闭游标变
量并释放经所点用的内存. 方法如下:
EXEC SQL FREE :cursor_name;
2、函数事例:
int DbsTblLineList (int nOpr) { int nList; int i; EXEC SQL DECLARE tbl_line_cfg_cur CURSOR FOR SELECT GATE_ID, LINE_IP, LINE_PORT FROM TBL_LINE_CFG ORDER BY GATE_ID; EXEC SQL OPEN tbl_line_cfg_cur; if (sqlca.sqlcode != 0) { printf (ERROR , "error code [%d], reason[%s] \n", sqlca.sqlcode, ( char * )sqlca.sqlerrm.sqlerrmc); return -1; } i = 0; nList = 1; while (1) { /*********************** * 从库表中FETCH数据,查询 ************************/ memset (saGateId, 0x00, sizeof(saGateId)); memset (saLineIp, 0x00, sizeof(saLineIp)); naLinePort = 0; EXEC SQL FETCH tbl_line_cfg_cur INTO :saGateId, :saLineIp, :naLinePort; if (sqlca.sqlcode != 0 && sqlca.sqlcode != 1403) { printf ("fetch tbl_line_cfg_cur error sqlcode[%d]", sqlca.sqlcode); EXEC SQL CLOSE tbl_line_cfg_cur; return -1; } if (sqlca.sqlcode == 1403) { EXEC SQL CLOSE tbl_line_cfg_cur; i++; lGateList[i].nList = -1; break; } lGateList[i].nList = nList; memcpy (lGateList[i].saGateId, saGateId, 2); memcpy (lGateList[i].saLineIp, saLineIp, 40); trimspace (lGateList[i].saLineIp); lGateList[i].naLinePort = naLinePort; i++; nList++; } return 0; }