博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PL/SQL 游标详解
阅读量:5148 次
发布时间:2019-06-13

本文共 9217 字,大约阅读时间需要 30 分钟。

刚打开游标的时候,是位于一个空行,要用fetch into 才能到第一行。

只是要注意用更新游标的时候,不能在游标期间commit. 否则会报ORA-01002: fetch out of sequence就是COMMIT导致的错误。
在打开有for update的cursor时,系统会给取出的数据加上排他锁(exclusive), 这样在这个锁释放前其他用户不能对这些记录作update、delete和加锁。
而我一旦执行了commit,锁就释放了,游标也变成无效的,再去fetch数据时就出现错误了。因而要把commit放在循环外,等到所有数据处理完成后再commit,然后关闭cursor
隐含游标
--------
又名SQL游标,用于处理单行select into 和 DML语句。
SQL%ISOPEN
SQL%FOUND
SQL%NOTFOUND
SQL%ROWCOUNT

显示游标

--------
用户处理select语句返回的多行数据。
select语句返回多行数据处理方式:[1]显示游标;[2]select ... bulk collect into 集合变量...;
【1】显示游标属性
[1] %ISOPEN 检测游标是否打开。
[2] %FOUND 检测游标结果集是否存在数据。
[3] %NOTFOUND 是否不存在数据。
[4] %ROWCOUNT 游标已提取的实际行数
【2】使用显示游标
[1] 定义游标
CURSOR cursor_name IS select_statement;
[2] 打开游标
OPEN cursor_name;
[3] 提取数据
FECTH cursor_name INTO variable,...
[4] 关闭数据
CLOSE cursor_name;
使用标量变量:

DECLARECursor emp_cur IS select ename,sal from emp order by empno;v_ename emp.ename%TYPE;v_sal   emp.sal%TYPE;BEGINIF NOT emp_cur%ISOPEN THEN   OPEN emp_cur;    DBMS_OUTPUT.PUT_LINE('打开游标');END IF;NULL;LOOP   FETCH emp_cur INTO v_ename,v_sal;   EXIT WHEN emp_cur%NOTFOUND;   DBMS_OUTPUT.PUT_LINE('用户名:'||v_ename||',工资:'||v_sal);END LOOP;NULL;IF emp_cur%ISOPEN THEN   CLOSE emp_cur;   DBMS_OUTPUT.PUT_LINE('关闭游标');END IF;END;

使用PLSQL记录变量:

DECLARECursor emp_cur IS select ename,sal from emp order by empno;emp_record emp_cur%ROWTYPE;BEGINIF NOT emp_cur%ISOPEN THEN   OPEN emp_cur;    DBMS_OUTPUT.PUT_LINE('打开游标');END IF;NULL;LOOP   FETCH emp_cur INTO emp_record;   EXIT WHEN emp_cur%NOTFOUND;   DBMS_OUTPUT.PUT_LINE('用户名:'||emp_record.ename||',工资:'||emp_record.sal);END LOOP;NULL;IF emp_cur%ISOPEN THEN   CLOSE emp_cur;   DBMS_OUTPUT.PUT_LINE('关闭游标');END IF;END;

使用PLSQL集合变量:

DECLARECursor emp_cur IS select ename,sal from emp order by empno;TYPE emp_table_type IS TABLE OF emp_cur%ROWTYPE INDEX BY BINARY_INTEGER;emp_table emp_table_type;i number;BEGINi := 1;IF NOT emp_cur%ISOPEN THEN   OPEN emp_cur;    DBMS_OUTPUT.PUT_LINE('打开游标');END IF;NULL;LOOP   FETCH emp_cur INTO emp_table(i);   EXIT WHEN emp_cur%NOTFOUND;   DBMS_OUTPUT.PUT_LINE('用户名:'||emp_table(i).ename||',工资:'||emp_table(i).sal);   i := i + 1;END LOOP;NULL;IF emp_cur%ISOPEN THEN   CLOSE emp_cur;   DBMS_OUTPUT.PUT_LINE('关闭游标');END IF;END;

【3】循环游标

FOR record_name IN cursor_name|select_statement LOOP
   statement;
 
....
END LOOP;

declare cursor emp_cusor is select ename,sal from emp where deptno = &no order by empno;beginfor emp_record in emp_cusor loop      dbms_output.put_line('姓名:'||emp_record.ename||',工资:'||emp_record.sal);end loop;end;beginfor emp_record in (select ename,sal from scott.emp where deptno = &no order by empno) loop      dbms_output.put_line('姓名:'||emp_record.ename||',工资:'||emp_record.sal);end loop;end;

【4】参数游标

CURSOR cursor_name(parameter_name datatype) IS select_statement;
--只能制定类型,不能指定具体大小
OPEN cursor_name(参数值);
FECTH cursor_name INTO
variable,...;
CLOSE cursor_name;

declare cursor emp_cursor(v_depnto number) is select ename,sal from scott.emp where deptno = v_depnto order by empno;emp_record emp_cursor%rowtype;v_dno number;beginv_dno := &no;if not emp_cursor%isopen then      open emp_cursor(v_dno);end if; null;loop        fetch emp_cursor into emp_record;         exit when emp_cursor%notfound;        dbms_output.put_line('姓名:'||emp_record.ename||',工资:'||emp_record.sal);end loop;null;if emp_cursor%isopen then       close emp_cursor;end if;end;
declare cursor emp_cursor(v_depnto number) is select ename,sal from scott.emp where deptno = v_depnto order by empno;v_dno number;beginv_dno := &no;for emp_record in emp_cursor(v_dno) loop      dbms_output.put_line('姓名:'||emp_record.ename||',工资:'||emp_record.sal);end loop;end;

【5】更新、删除游标行

CURSOR cursor_name IS select_statement
FOR UPDATE [OF column_reference] [NOWAITE];   -- OF子句指定对特定表加锁。
UPDATE table_name SET column=.. WHERE CURRENT OF cursor_name;
DELETE table_name WHERE CURRENT OF cursor_name;

declare       cursor test_cursor is select empno,ename,sal,deptno from scott.test for update;       test_record test_cursor%rowtype;       v_deptno number;       v_sal test.sal%type;begin       v_deptno := &no;       if not test_cursor%isopen then          open test_cursor;       end if;       loop          fetch test_cursor into test_record;          exit when test_cursor%notfound;          dbms_output.put_line('姓名:'||test_record.ename||',旧工资:'||test_record.sal);          if test_record.deptno = v_deptno then             update scott.test set sal=2*sal where current of test_cursor;          else             update scott.test set sal=3*sal where current of test_cursor;          end if;       end loop;       close test_cursor;end;       declarecursor test_cursor is select empno,ename,sal,deptno from scott.test for update;      v_deptno NUMBER:=&dno;beginfor test_record in test_cursor loop        if test_record.deptno = v_deptno then                 dbms_output.put_line('姓名:'||test_record.ename||',旧工资:'||test_record.sal);                 update scott.test set sal = sal*1.5 where current of test_cursor;           end if;       end loop;end;

使用游标删除数据

declare cursor test_cursor(v_deptno number) is select deptno,empno,ename,comm from scott.test where deptno = v_deptno for update;v_dno test.deptno%type := &dno;begin     for test_record in test_cursor(v_dno) loop         if test_record.comm is null then            dbms_output.put_line('用户名:'||test_record.ename||'部门:'||test_record.deptno);            delete from scott.test where current of test_cursor;         end if;     end loop;     end;

【6】游标变量

指向内存地址的指针。可以在打开游标时指定其所对应的SELECT语句,实现动态游标。
[1]定义REF CURSOR类型和游标变量:
Type ref_type_name IS REF CURSOR [RETURN return_type --必须是PL/SQL记录类型];
说明:如果指定RETURN子句,那么在打开游标时SELECT语句的返回结果必须与RETURN子句所指定的记录类型匹配。
cursor_variable ref_type_name;
SYS_REFCURSOR
[2]打开游标,指定对应的SELECT语句:
OPEN cursor_variable FOR select_statement;
[3]提取数据
FETCH cursor_variable INTO variable1,variable,...;
[4]关闭游标
CLOSE cursor_variable;
不使用RETURN子句
----------------

DECLARETYPE ref_type_table IS REF CURSOR;v_cursor            ref_type_table;emp_record          emp%rowtype;BEGIN     OPEN v_cursor FOR select * from emp where deptno=&no;     LOOP         FETCH v_cursor INTO emp_record;         EXIT WHEN v_cursor%NOTFOUND;         dbms_output.put_line('员工号:'||emp_record.ename||'部门号:'||emp_record.deptno);     END LOOP;     CLOSE v_cursor;END;

使用RETURN子句

--------------

DECLAREemp_record          emp%rowtype;TYPE ref_type_table IS REF CURSOR RETURN emp%rowtype;v_cursor            ref_type_table;BEGIN     OPEN v_cursor FOR select * from emp where deptno=&no;     LOOP         FETCH v_cursor INTO emp_record;         EXIT WHEN v_cursor%NOTFOUND;         dbms_output.put_line('员工号:'||emp_record.ename||'部门号:'||emp_record.deptno);     END LOOP;     CLOSE v_cursor;END;DECLAREType emp_record_type IS RECORD(       ename emp.ename%TYPE,       salary emp.sal%TYPE,       deptno emp.deptno%TYPE);emp_record emp_record_type;TYPE ref_type_table IS REF CURSOR RETURN emp_record_type;v_cursor            ref_type_table;BEGIN     OPEN v_cursor FOR select ename,sal,deptno from emp where deptno=&no;     LOOP         FETCH v_cursor INTO emp_record;         EXIT WHEN v_cursor%NOTFOUND;         dbms_output.put_line('员工号:'||emp_record.ename||',部门号:'||emp_record.deptno||',工资:'||emp_record.salary);     END LOOP;     CLOSE v_cursor;END;

【7】使用游标批量获取

FETCH ... BULK COLLECT INTO ...[LIMIT row_number];

不限制行数

----------

DECLARE     CURSOR emp_cursor(v_deptno number) IS SELECT * FROM EMP WHERE deptno = v_deptno;     TYPE type_emp_table IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;     emp_table type_emp_table;     v_dno emp.deptno%TYPE;BEGIN     v_dno := &no;     OPEN emp_cursor(v_dno);     FETCH emp_cursor BULK COLLECT INTO emp_table;     CLOSE emp_cursor;     FOR i IN 1..emp_table.COUNT LOOP         dbms_output.put_line('员工号:'||emp_table(i).ename||'工资:'||emp_table(i).sal);     END LOOP;     CLOSE emp_cursor;END;

限制行数

--------

DECLARE     CURSOR emp_cursor(v_deptno number) IS SELECT * FROM EMP WHERE deptno = v_deptno;     TYPE type_emp_table IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;     emp_table type_emp_table;     v_dno emp.deptno%TYPE;BEGIN     v_dno := &no;     OPEN emp_cursor(v_dno);     FETCH emp_cursor BULK COLLECT INTO emp_table LIMIT &2;     CLOSE emp_cursor;     FOR i IN 1..emp_table.COUNT LOOP         dbms_output.put_line('员工号:'||emp_table(i).ename||'工资:'||emp_table(i).sal);     END LOOP;     CLOSE emp_cursor;END;

【8】使用CURSOR表达式

作用嵌套游标。

DECLARE       CURSOR dept_emp_cursor(v_deptno number) IS    SELECT dname,cursor(SELECT * FROM emp e WHERE e.deptno = d.deptno)    FROM dept d WHERE deptno = v_deptno;       TYPE emp_cursor_type IS REF CURSOR;       emp_cursor emp_cursor_type;       emp_record emp%ROWTYPE;       v_name dept.dname%TYPE;       v_dno emp.deptno%TYPE;BEGIN     v_dno := &no;     OPEN dept_emp_cursor(v_dno);     loop           FETCH dept_emp_cursor INTO v_name,emp_cursor;          EXIT WHEN dept_emp_cursor%NOTFOUND;          dbms_output.put_line('部门名称:'||v_name);          LOOP              FETCH emp_cursor INTO emp_record;                          EXIT WHEN emp_cursor%NOTFOUND;              dbms_output.put_line('员工名称:'||emp_record.ename||',工资:'||emp_record.sal);          END LOOP;     end loop;     CLOSE dept_emp_cursor;END;

 

转载于:https://www.cnblogs.com/nuaa/p/3749906.html

你可能感兴趣的文章
贝索斯发布年度致股东信:亚马逊要高标准满足客户-20180420
查看>>
C#-WebForm JS定时器(转)
查看>>
Web —— java web 项目 Tomcat 的配置 与 第一个web 项目创建
查看>>
C#实验——Glossary
查看>>
maven项目中添加Tomcat启动插件
查看>>
关联查询中的一对一查询。通过第一种方式也就是自动映射的方式查询所有订单信息,关联查询下单用户信息。(由于需要创建中间类,这种方法在实际开发中已经不再使用)...
查看>>
【编程思想】【设计模式】【行为模式Behavioral】备忘录模式Memento
查看>>
Oracle创建分区表
查看>>
Android深度探索第九章
查看>>
hdu 2393:Higher Math(计算几何,水题)
查看>>
windows下用tcc编译Lua
查看>>
execl导入导出
查看>>
phpcms和php格式化时间戳
查看>>
thinkphp的空控制器和空操作以及对应解决方法
查看>>
hadoop记录-MapReduce之如何处理失败的task(转载)
查看>>
TCP介绍
查看>>
POJ 2823 Sliding Window
查看>>
如何修改mysql数据库文件的路径
查看>>
CSS3笔记4
查看>>
约瑟夫问题
查看>>