PL/SQL: ORA-01001 在游标使用中

PL/SQL: ORA-01001 in cursor use

我正在编写一个 PL/SQL 函数来检查日期和 return 一个日期。 问题是测试隔离的功能我得到了关于光标使用的错误。 ORA-01001: cursor no válido or in english, not valid cursor.

我使用两个数组来保存不同类型的日期。 但是错误出现在 FOR ... LOOP 循环中。先验是明确定义游标和行变量。 我已经检查过并且行变量包含行,查询 returns 至少有 5 行。 这里是函数的代码:

create or replace FUNCTION OBTAIN_DATE_FIN_ABSENT
            (combination IN VARCHAR2 DEFAULT '',
            otarif1 IN VARCHAR2 DEFAULT '',
            otarif2 IN VARCHAR2 DEFAULT '',
            indicador IN NUMBER DEFAULT 0) 
           RETURN DATE 
        AS 
            i NUMBER := 1;
            solution DATE := '01/01/1970';
            previousOTARi VARCHAR2(3 CHAR) := '';

            TYPE varray_type IS VARRAY(50) OF DATE; -- Création deux arrays des dates.
            v1 varray_type;                         -- array date_begin
            v2 varray_type;                         -- array date_end

            -- Requete pour obtenir tous les lignes pour la combinaison passé.
            cursor cursorDate is            
                select cin.cin_value cin_combi, cin.date_begin date_begin, cin.date_end date_end, gin.code gcode, gin.otari_file otari_file 
                from rs2qtcin cin, rs2qtgin gin
                where cin.group_id = gin.id
                and cin.cin_value = combination
                and substr(gin.otari_file, 1, 1) = substr(otarif1, 1, 1)
                order by cin.date_begin, gin.otari_file;
            my_cursorDate cursorDate%rowtype;
        BEGIN
           --open cursorDate;
           DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- Dentro!');
           FETCH cursorDate INTO my_cursorDate;
           DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- Dentro1!');
           IF cursorDate%FOUND THEN         -- El cursor contiene info, sino %NOTFOUND
                DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- Dentro2!');
                IF cursorDate%ROWCOUNT != 0 THEN
                    DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- cursor NO vacío!');
                ELSE
                    DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- cursor VACÍO!!!');
                END IF;
            ELSE
                DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- Cursor NOTFOUND!');
            END IF;

            FOR my_cursorDate IN cursorDate LOOP
                DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- Dentro3!');
                --v1(i) := my_cursorDate.date_begin;
                --v2(i) := my_cursorDate.date_end;
                DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- Guardadas ambas fechas en array!.');

                IF v2(i-1) = NULL THEN
                    --solution := v1(i); -- Guardamos date_begin de la siguiente iteración

                    IF indicador = 1 and previousOTARi = otarif1 THEN
                        DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- OK!');
                    ELSE 
                        IF indicador = 2 and previousOTARi = otarif2 THEN
                            DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- ¡CHECK! this case.');
                        END IF;
                    END IF;
                END IF;
                --solution := 1;
                previousOTARi := my_cursorDate.otari_file;
                i := i+1;
           END LOOP;

           --close cursorDate;

        RETURN solution;

        EXCEPTION WHEN OTHERS THEN
            raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);    
        END;

Open 和 close cursor 语句被注释了,因为我正在调试代码。但是当它们被取消注释时,错误是一样的。

打开光标后,您需要将其关闭。

此外,我已将您的光标更改为使用现代显式连接。

这部分我也修改了你的代码FOR rec IN cursorDate LOOP

create or replace FUNCTION OBTAIN_DATE_FIN_ABSENT
            (combination IN VARCHAR2 DEFAULT '',
             otarif1 IN VARCHAR2 DEFAULT '',
             otarif2 IN VARCHAR2 DEFAULT '',
             indicador IN NUMBER DEFAULT 0) 
RETURN DATE 
AS 

i NUMBER := 1;
solution DATE := '01/01/1970'; 
previousOTARi VARCHAR2(50) := '';

TYPE varray_type IS VARRAY(50) OF DATE; 
v1 varray_type;                
v2 varray_type;                         


cursor cursorDate is            
select cin.cin_value cin_combi
       , cin.date_begin date_begin
       , cin.date_end date_end
       , gin.code gcode
       , gin.otari_file otari_file 
from rs2qtcin cin
join rs2qtgin gin on cin.group_id = gin.id
                 and cin.cin_value = gin.combination
                 and substr(gin.otari_file, 1, 1) = substr(cin.otarif1, 1, 1)
order by cin.date_begin, gin.otari_file;

my_cursorDate cursorDate%rowtype;

BEGIN
    open cursorDate;
    FETCH cursorDate INTO my_cursorDate;

    IF cursorDate%FOUND THEN         -- El cursor contiene info, sino %NOTFOUND
        DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- Dentro2!');
        IF cursorDate%ROWCOUNT != 0 THEN
            DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- cursor NO vacío!');
        ELSE
            DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- cursor VACÍO!!!');
       END IF;
    ELSE
       DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- Cursor NOTFOUND!');
    END IF;
    close cursorDate;

    FOR rec IN cursorDate LOOP
       DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- Dentro3!');
       DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- Guardadas ambas fechas en array!.');

       IF v2(i-1) = NULL THEN
          IF indicador = 1 and previousOTARi = otarif1 THEN
             DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- OK!');
          ELSE 
             IF indicador = 2 and previousOTARi = otarif2 THEN
                DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- ¡CHECK! this case.');
             END IF;
          END IF;
       END IF;

       previousOTARi := my_cursorDate.otari_file;
       i := i+1;
    END LOOP;

    RETURN solution;

EXCEPTION WHEN OTHERS THEN
    raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);    
END;
/

Here is a demo showing the code works

您的程序存在一些结构性问题。最紧迫的问题是 "open and close cursor statement are commented because i'm debugging the code"。因为 open 在注释中 FETCH 失败并带有无效游标 - fetch 需要打开游标。您声称错误是在游标 FOR 循环上发出的。我想那是在您评论开放之前。游标 FOR 为游标发出一个打开。其中,如果游标打开,则抛出无效游标。您不能在打开的游标上使用游标 FOR。因此,您要么打开游标,处理第一行(获取),然后关闭游标,然后输入 FOR。退出循环后不要关闭游标。

您在嵌套 if 结构中存在逻辑问题。

IF cursorDate%FOUND THEN         -- El cursor contiene info, sino %NOTFOUND
   DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- Dentro2!');
   IF cursorDate%ROWCOUNT != 0 THEN
      DBMS_OUTPUT.PUT_LINE ('OBTAIN_DATE_FIN_ABSENT -- cursor NO vacío!');
   ELSE

"if cursorDate%Rowcount != 0" 将始终 return 为真。游标属性 %rowcount returns 从游标中获取的行数。如果最后一次提取 return 一行,属性 %Found returns 为真。因为这里 %Rowcount 是从属的 %Found 意味着它永远不会 return 小于 1。

另一个显而易见的语句是

IF v2(i-1) = NULL THEN 

它有两个问题。首先,你的变量 i 被初始化为 1,所以上面的语句然后读取 v2(0)。这是无效的,pl/sql 中的索引值以 1 开头。一旦正确,结果语句将永远不会为真。您不能将关系运算符与 Null 一起使用;这样做的结果始终为 Null。你需要 "v2(i) is Null"。
如果您仍然有问题,请解决这些问题 post 另一个问题。