PL/SQL--Cursor

PL/SQL--Cursor

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

游标的概念:

游标给出了数据的一个子集,这个子集是由某个查询语句定义的,在打开游标的时候,将数据加载到内存中,在游标未关闭的过程中,该数据将一直存在在内存中,游标指向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;
复制代码




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值