PL/SQLCursor

显式游标
隐式游标
游标变量
游标子查询

游标的概念:

 游标给出了数据的一个子集,这个子集是由某个查询语句定义的,在打开游标的时候,将数据加载到内存中,在游标未关闭的过程中,该数据将一直存在在内存中,游标指向PGA(PROCESS GLOBAL AREA)的一个内存区域,一般将PGA称为上下文区域。该区域存储下列数据:

  1、查询语句返回的记录行。

  2、查询语句处理的记录行数目。

  3、指向共享池中(Share Pool)中已解析查询语句的一个指针。

如果游标打开后,又新增或者删除了数据,则新增添和删除的数据就不会反馈到游标的查询结果中,打开游标就像是获取当前数据的一个快照:例如

 1 DECLARE
2 V_ROWID ROWID;
3 CURSOR DEPT_CURSOR_1 IS
4 SELECT ROWID FROM TEST_DEPT T WHERE T.DEPTNO < 100;
5 CURSOR DEPT_CURSOR_2 IS
6 SELECT ROWID FROM TEST_DEPT T WHERE T.DEPTNO < 100;
7 BEGIN
8 --打开游标1,将其中的数据删除
9 OPEN DEPT_CURSOR_1;
10 DELETE FROM TEST_DEPT T WHERE T.DEPTNO < 100;
11 --打开游标2
12 OPEN DEPT_CURSOR_2;
13
14 --检查游标1
15 FETCH DEPT_CURSOR_1
16 INTO V_ROWID;
17 IF DEPT_CURSOR_1%ROWCOUNT > 0 THEN
18 DBMS_OUTPUT.PUT_LINE('游标1包含删除的数据');
19 ELSE
20 DBMS_OUTPUT.PUT_LINE('游标1不包含删除的数据');
21 END IF;
22 --检查游标1
23 FETCH DEPT_CURSOR_2
24 INTO V_ROWID;
25 IF DEPT_CURSOR_2%ROWCOUNT > 0 THEN
26 DBMS_OUTPUT.PUT_LINE('游标2包含删除的数据');
27 ELSE
28 DBMS_OUTPUT.PUT_LINE('游标2不包含删除的数据');
29 END IF;
30 CLOSE DEPT_CURSOR_1;--关闭游标
31 CLOSE DEPT_CURSOR_2;
32 ROLLBACK;--回滚
33 EXCEPTION WHEN OTHERS THEN
34 DBMS_OUTPUT.PUT_LINE(Sqlerrm);
35 END;

结果:

--显式游标的四个属性
/*%ROWCOUNT
%FOUND
%NOTFOUND
%ISOPEN*/

 1 --定义一个游标
2 DECLARE
3 CURSOR EMP_CURSOR_1 IS(
4 SELECT * FROM EMP);
5 CURSOR EMP_CURSOR_2 IS(
6 SELECT * FROM EMP);
7 V_EMP_RECORD EMP%ROWTYPE;
8 BEGIN
9 --打开游标1
10 IF NOT EMP_CURSOR_1%ISOPEN THEN
11 OPEN EMP_CURSOR_1;
12 DBMS_OUTPUT.PUT_LINE('OPEN CURSOR1');
13 END IF;
14 --提取数据--使用基本LOOP循环
15 LOOP
16 FETCH EMP_CURSOR_1
17 INTO V_EMP_RECORD;
18 DBMS_OUTPUT.PUT_LINE('ENAME:' || V_EMP_RECORD.ENAME);
19 EXIT WHEN EMP_CURSOR_1%NOTFOUND;
20 END LOOP;
21 CLOSE EMP_CURSOR_1;
22 OPEN EMP_CURSOR_1;
23 --提取数据--使用WHILE-----LOOP循环
24 WHILE EMP_CURSOR_1%FOUND LOOP
25 FETCH EMP_CURSOR_1
26 INTO V_EMP_RECORD;
27 DBMS_OUTPUT.PUT_LINE('ENAME:' || V_EMP_RECORD.ENAME);
28 END LOOP;
29 --关闭游标
30 IF EMP_CURSOR_1%ISOPEN THEN
31 CLOSE EMP_CURSOR_1;
32 DBMS_OUTPUT.PUT_LINE('CLOSE CURSOR');
33 END IF;
34 DBMS_OUTPUT.PUT_LINE('=============分隔符==============');
35 --提取数据--使用FOR-----LOOP循环.使用这种循环,会自动的打开和关闭游标
36 FOR IDX IN EMP_CURSOR_2 LOOP
37 DBMS_OUTPUT.PUT_LINE('ENAME:' || IDX.ENAME);
38 END LOOP;
39 --测试%ROWCOUNT属性
40 OPEN EMP_CURSOR_1;
41 FETCH EMP_CURSOR_1
42 INTO V_EMP_RECORD;
43 DBMS_OUTPUT.PUT_LINE('ROWCOUNT' || EMP_CURSOR_1%ROWCOUNT);
44 CLOSE EMP_CURSOR_1;
45 DBMS_OUTPUT.PUT_LINE(CHR(1));
46 END;

--隐式游标的四个属性

SQL%ROWCOUNT
SQL%FOUND
SQL%NOTFOUND
SQL%ISOPEN--永远为FALSE

1 DECLARE
2 V_DEPTNO DEPT.DEPTNO%TYPE := &部门编号;
3 BEGIN
4 UPDATE TEST_DEPT T SET T.LOC = '西安市' WHERE T.DEPTNO = V_DEPTNO;
5 IF SQL%NOTFOUND THEN
6 DBMS_OUTPUT.PUT_LINE('没有该部门');
7 END IF;
8 END;


在进行更新操作的过程中,最好使用for update,可以添加nowait,当该行数据被其他锁定时,会提示:

1  DECLARE
2 CURSOR EMP_TEST_CUR IS
3 SELECT * FROM EMP_TEST FOR UPDATE OF ENAME NOWAIT;
4 BEGIN
5 FOR EMP_REC IN EMP_TEST_CUR LOOP
6 UPDATE EMP_TEST SET ename = '小明' WHERE CURRENT OF EMP_TEST_CUR;
7 END LOOP;
8 END;

--游标变量的使用

 1 --游标变量的使用
2 DECLARE
3 TYPE EMP_CURSOR IS REF CURSOR RETURN EMP%ROWTYPE;
4 V_EMP_CURSOR EMP_CURSOR;
5 V_EMP_RECORD EMP%ROWTYPE;
6 BEGIN
7 --打开游标,使用FOR来赋初始值
8 OPEN V_EMP_CURSOR FOR
9 SELECT * FROM EMP;
10 --提取数据
11 FETCH V_EMP_CURSOR
12 INTO V_EMP_RECORD;
13 --输出数据
14 DBMS_OUTPUT.PUT_LINE('DEPTNO:' || V_EMP_RECORD.DEPTNO ||
15 'ENAME:' || V_EMP_RECORD.ENAME);
16 CLOSE V_EMP_CURSOR;
17 END;

--游标子查询

 1 --游标子查询
2 DECLARE
3 EMP_CURSOR SYS_REFCURSOR;
4 EMP_RECORD EMP%ROWTYPE;
5 DEPT_NAME DEPT.DNAME%TYPE;
6 CURSOR DEPT_CURSOR IS
7 SELECT D.DNAME, CURSOR (SELECT * FROM EMP E WHERE E.DEPTNO = D.DEPTNO)
8 FROM DEPT D;
9 BEGIN
10 OPEN DEPT_CURSOR;
11 LOOP
12 FETCH DEPT_CURSOR
13 INTO DEPT_NAME, EMP_CURSOR;
14 EXIT WHEN DEPT_CURSOR%NOTFOUND;
15 DBMS_OUTPUT.PUT_LINE('DNAME:' || DEPT_NAME);
16 LOOP
17 FETCH EMP_CURSOR
18 INTO EMP_RECORD;
19 EXIT WHEN EMP_CURSOR%NOTFOUND;
20 DBMS_OUTPUT.PUT_LINE('ENAME:' || EMP_RECORD.ENAME);
21 END LOOP;
22 END LOOP;
23 END;

REF_CURSOR的使用:

 1 DECLARE
2 TYPE EMP_CURSOR_REF IS REF CURSOR;
3 EMP_CURSOR EMP_CURSOR_REF;
4 EMP_RECORD EMP%ROWTYPE;
5 BEGIN
6 OPEN EMP_CURSOR FOR
7 SELECT * FROM EMP;
8 FETCH EMP_CURSOR
9 INTO EMP_RECORD;
10 WHILE EMP_CURSOR%FOUND LOOP
11 DBMS_OUTPUT.PUT_LINE('ename:' || EMP_RECORD.ENAME);
12 FETCH EMP_CURSOR
13 INTO EMP_RECORD;
14 END LOOP;
15 END;

游标和varray的联合使用

 1 DECLARE
2 TYPE EMP_VARRAY IS VARRAY(100) OF EMP%ROWTYPE;
3 EMPS EMP_VARRAY;
4 CURSOR EMP_CURSOR IS
5 SELECT * FROM EMP;
6 COUNTS PLS_INTEGER := 0;
7 BEGIN
8 --初始化数组(下标从1开始)
9 EMPS := EMP_VARRAY();
10 FOR IDX IN EMP_CURSOR LOOP
11 --添加一行新数据
12 COUNTS := COUNTS + 1;
13 EMPS.EXTEND();
14 EMPS(COUNTS).EMPNO := IDX.EMPNO;
15 EMPS(COUNTS).ENAME := IDX.ENAME;
16 EMPS(COUNTS).JOB := IDX.JOB;
17 EMPS(COUNTS).MGR := IDX.MGR;
18 EMPS(COUNTS).HIREDATE := IDX.HIREDATE;
19 EMPS(COUNTS).SAL := IDX.SAL;
20 EMPS(COUNTS).COMM := IDX.COMM;
21 EMPS(COUNTS).DEPTNO := IDX.DEPTNO;
22 END LOOP;
23
24 FOR IDX1 IN 1 .. EMPS.COUNT LOOP
25 DBMS_OUTPUT.PUT_LINE('empno:' || EMPS(IDX1).EMPNO);
26 END LOOP;
27 END;






I believe that we are who we choose to be. Nobody‘s going to come and save you, you‘ve got to save yourself. 我相信我们成为怎样的人是我们自己的选择。没有人会来拯救你,你必须要自己拯救自己。
原文地址:https://www.cnblogs.com/caroline/p/2284292.html