1.神马是游标?
游标可以理解为数据表的指针,指向数据表的某一行记录。有些人可能会说如果游标的查询语句不是作用在一张表,而是多张表的联合查询。那么这里的指向的数据库肯定不是某个具体的数据库,而是一个虚拟的表(virtual table,只临时存在于查询期间)。
2.游标分为静态和动态,静态游标又分成了隐式游标和显示游标。动态游标分成了强类型动态游标和弱类型动态游标。
隐式游标:由oracle rdbms 自动创建,针对UPDATE 、DELETE、SELECT、INSERT 语句(不管这些语句是否只返回一条记录,返回多条记录一样会创建隐式游标)。
隐式游标属性:ISOPEN属性都是false,说明隐式属性没法被我们程序猿控制。
INSERT, UPDATE, DELETE, SELECT 语句中不必明确定义游标。
隐式游标属性
属性
值
SELECT
INSERT
UPDATE
DELETE
SQL%ISOPEN
FALSE
FALSE
FALSE
FALSE
SQL%FOUND
TRUE
有结果
成功
成功
SQL%FOUND
FALSE
没结果
失败
失败
SQL%NOTFUOND
TRUE
没结果
失败
失败
SQL%NOTFOUND
FALSE
有结果
成功
失败
SQL%ROWCOUNT
返回行数,只为1
插入的行数
修改的行数
删除的行数
声明游标:
CURSOR CUR_NAME (parameter1 IN datatype1,parameter2 IN datatype2) RETURN rec_type
IS select_sentence
参数解释:CUR_NAME是游标名称。
parameter1是参数1,dataype1是参数1的数据类型。
rec_type 是返回的记录类型。
select_sentence 是查询语句。
例子:
CURSOR emp_cur IS SELECT * FROMemp;
打开游标:OPEN CUR_NAME;
打开游标的过程就已经按照查询语句查询出了结果集(即select语句查询出的虚拟表),只不过这个结果集还没有被取出。所以游标的取数定位在开启游标那个时候,开启游标之后的数据并不管。
从游标中取回数据:
FETCH cur_name INTO rec_name;
将取出的记录放到记录类型中。
游标中列的别名:
游标中使用了别名后,在将数取到记录后,记录中的列只能通过别名来定位.
例:
DECLARE
CURSOR emp_cur IS SELECT ename xm,job gw FROM emp;
emp_rec emp_cur%ROWTYPE;
BEGIN
OPEN emp_cur;
FETCH emp_cur INTO emp_rec;
WHILE emp_cur%FOUND LOOP
Dbms_Output.put_line(emp_rec.xm||'-----'||emp_rec.gw);
FETCH emp_cur INTO emp_rec;
END LOOP;
CLOSE emp_cur;
END;
关闭游标:
CLOSE cur_name;打开游标会占用系统全局内存,因此使用后一定要关闭游标。
游标属性:
%FOUND,%NOTFOUND,%ISOPEN,%ROWCOUND
游标参数:
游标参数的模式只有IN ,格式为 parameter1 IN datatype1
作用于为游标查询语句内,其他任何地方都无效。
强类型游标:指定返回类型
声明:DECLARE
TYPE cur_name IS REF CURSOR RETURN rec_type;
obj_cur cur_name;
...
OPEN obj_cur FOR select_sentence
弱类型游标:不指定返回类型
声明:DECLARE
TYPE cur_name IS REF CURSOR ;
obj_cur cur_name;
...
OPEN obj_cur FOR select_sentence
解释:
type cur_name is ref cursor 是声明一个弱游标类型
obj_cur cur_name; 声明一个弱类型的游标对象
open obj_cur for 对游标对象赋值
有必要在提一下游标对象的作用域:游标对象的作用域局限在begin end之间。确切的说是在声明游标的pl/sql块中
将游标变量作为参数传递:
DECLARE
TYPE emp_cur IS REF CURSOR;
emps emp_cur;
emp_rec emp%ROWTYPE;
PROCEDURE getEmpByDeptno
(deptnum IN NUMBER,emps OUT emp_cur) IS
BEGIN
OPEN emps FOR SELECT * FROM emp WHERE deptno=deptnum;
END;
BEGIN
getEmpByDeptno(20,emps);
LOOP
FETCH emps INTO emp_rec;
DBMS_OUTPUT.put_line(emp_rec.ename);
EXIT WHEN emps%NOTFOUND;
END LOOP;
CLOSE emps;
END;
for循环游标
for循环游标省去了打开,取数,关闭游标的一系列操作。
DECLARE
CURSOR emp_cur IS SELECT * FROM emp;
total_salary INTEGER :=0;
BEGIN
FOR emp_cc IN emp_cur LOOP
total_salary := total_salary+emp_cc.sal;
END LOOP;
DBMS_OUTPUT.put_line(total_salary);
END;
这里emp_cc自动被声明为了记录类型(emp_cur%rowtype)