每个游标都有一组与之关联的属性,允许程序测试游标的状态。这些属性是 %ISOPEN、%FOUND、%NOTFOUND 和 %ROWCOUNT。以下各节介绍了这些属性。

%ISOPEN

%ISOPEN 属性用于测试游标是否已打开。

cursor_name%ISOPEN

cursor_name 是游标的名称,如果游标打开,将返回 BOOLEAN 数据类型 TRUE,否则将返回 FALSE。

下面是使用 %ISOPEN 的示例。

CREATE OR REPLACE PROCEDURE cursor_example
IS
        ...
    CURSOR emp_cur_1 IS SELECT * FROM emp;
        ...
BEGIN
        ...
    IF emp_cur_1%ISOPEN THEN
        NULL;
    ELSE
        OPEN emp_cur_1;
    END IF;
    FETCH emp_cur_1 INTO ...
        ...
END;

%FOUND

%FOUND 属性用于测试在对游标执行 FETCH 操作之后是否从指定游标的结果集中检索到行。

cursor_name%FOUND

cursor_name 是游标的名称,如果在 FETCH 之后从游标的结果集中检索到行,则将返回BOOLEAN 数据类型 TRUE。

在结果集的最后一行被 FETCH 之后,下一个 FETCH 将导致 %FOUND 返回 FALSE。如果结果集中没有行,则第一个 FETCH 之后也会返回 FALSE。

在游标打开之前或关闭游标之后对游标引用 %FOUND 会导致引发 INVALID_CURSOR 异常。

如果游标已打开,但在第一个 FETCH 之前引用 %FOUND,它将返回 null。

以下示例使用 %FOUND。

CREATE OR REPLACE PROCEDURE cursor_example
IS
    v_emp_rec       emp%ROWTYPE;
    CURSOR emp_cur_1 IS SELECT * FROM emp;
BEGIN
    OPEN emp_cur_1;
    DBMS_OUTPUT.PUT_LINE('EMPNO    ENAME');
    DBMS_OUTPUT.PUT_LINE('-----    -------');
    FETCH emp_cur_1 INTO v_emp_rec;
    WHILE emp_cur_1%FOUND LOOP
        DBMS_OUTPUT.PUT_LINE(v_emp_rec.empno || '     ' || v_emp_rec.ename);
        FETCH emp_cur_1 INTO v_emp_rec;
    END LOOP;
    CLOSE emp_cur_1;
END;

调用前面的存储过程时,输出显示如下:

EXEC cursor_example;

EMPNO    ENAME
-----    ------
7369     SMITH
7499     ALLEN
7521     WARD
7566     JONES
7654     MARTIN
7698     BLAKE
7782     CLARK
7788     SCOTT
7839     KING
7844     TURNER
7876     ADAMS
7900     JAMES
7902     FORD
7934     MILLER

%NOTFOUND

%NOTFOUND 属性是 %FOUND 的逻辑对立面。

cursor_name%NOTFOUND

cursor_name 是游标的名称,如果在 FETCH 之后从游标的结果集中检索到行,则将返回BOOLEAN 数据类型 FALSE。

在结果集的最后一行被 FETCH 之后,下一个 FETCH 将导致 %NOTFOUND 返回 TRUE。如果结果集中没有行,则第一个 FETCH 之后也会返回 TRUE。

在游标打开之前或关闭游标之后对游标引用 %NOTFOUND 会导致引发 INVALID_CURSOR 异常。

如果游标已打开,但在第一个 FETCH 之前引用 %NOTFOUND,它将返回 null。

以下示例使用 %NOTFOUND。

CREATE OR REPLACE PROCEDURE cursor_example
IS
    v_emp_rec       emp%ROWTYPE;
    CURSOR emp_cur_1 IS SELECT * FROM emp;
BEGIN
    OPEN emp_cur_1;
    DBMS_OUTPUT.PUT_LINE('EMPNO    ENAME');
    DBMS_OUTPUT.PUT_LINE('-----    -------');
    LOOP
        FETCH emp_cur_1 INTO v_emp_rec;
        EXIT WHEN emp_cur_1%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE(v_emp_rec.empno || '     ' || v_emp_rec.ename);
    END LOOP;
    CLOSE emp_cur_1;
END;

与前面的示例类似,此存储过程在调用时会生成相同的输出。

EXEC cursor_example;

EMPNO    ENAME
-----    ------
7369     SMITH
7499     ALLEN
7521     WARD
7566     JONES
7654     MARTIN
7698     BLAKE
7782     CLARK
7788     SCOTT
7839     KING
7844     TURNER
7876     ADAMS
7900     JAMES
7902     FORD
7934     MILLER

%ROWCOUNT

%ROWCOUNT 属性返回一个整数,显示到目前为止通过 FETCH 从指定游标获取的行数。

cursor_name%ROWCOUNT

cursor_name 是游标的名称,%ROWCOUNT 对其返回到目前为止检索的行数。在检索到最后一行之后,%ROWCOUNT 仍然设置为在游标关闭之前返回的总行数,此时如果引用%ROWCOUNT,它将引发 INVALID_CURSOR 异常。

在游标打开之前或关闭游标之后对游标引用 %ROWCOUNT 会导致引发 INVALID_CURSOR 异常。

如果游标已打开,但在第一个 FETCH 之前引用 %ROWCOUNT,它将返回 0。如果结果集中没有行,%ROWCOUNT 也会在第一个 FETCH 后返回 0。

以下示例使用 %ROWCOUNT。

CREATE OR REPLACE PROCEDURE cursor_example
IS
    v_emp_rec       emp%ROWTYPE;
    CURSOR emp_cur_1 IS SELECT * FROM emp;
BEGIN
    OPEN emp_cur_1;
    DBMS_OUTPUT.PUT_LINE('EMPNO    ENAME');
    DBMS_OUTPUT.PUT_LINE('-----    -------');
    LOOP
        FETCH emp_cur_1 INTO v_emp_rec;
        EXIT WHEN emp_cur_1%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE(v_emp_rec.empno || '     ' || v_emp_rec.ename);
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('**********************');
    DBMS_OUTPUT.PUT_LINE(emp_cur_1%ROWCOUNT || ' rows were retrieved');
    CLOSE emp_cur_1;
END;

此存储过程输出在员工列表末尾检索的总行数,如下所示:

EXEC cursor_example;

EMPNO    ENAME
-----    -------
7369     SMITH
7499     ALLEN
7521     WARD
7566     JONES
7654     MARTIN
7698     BLAKE
7782     CLARK
7788     SCOTT
7839     KING
7844     TURNER
7876     ADAMS
7900     JAMES
7902     FORD
7934     MILLER
**********************
14 rows were retrieved

游标状态和属性摘要

下表总结了可能的游标状态和游标属性返回的值。

游标状态 %ISOPEN %FOUND %NOTFOUND %ROWCOUNT
在OPEN 之前 False INVALID_CURSOR异常 INVALID_CURSOR异常 INVALID_CURSOR异常
在OPEN之后,第一个FETCH 之前 True Null Null 0
第一个成功的FETCH 之后 True True False 1
第n个成功的FETCH之后(最后一行) True True False n
第n+1 个FETCH之后(最后一行之后) True False True n
在CLOSE 之后 False INVALID_CURSOR异常 INVALID_CURSOR异常 INVALID_CURSOR异常