PL / SQL: ORA-01001 в использовании курсора - PullRequest
0 голосов
/ 23 марта 2020

Я программирую функцию PL / SQL для проверки дат и возврата даты. Проблема в том, что при тестировании изолированной функции я получил ошибку об использовании курсора. ORA-01001: курсор не имеет значения или по-английски sh, недопустимый курсор.

Я использую два массива для сохранения дат различного типа. Но ошибка приходит в FOR ... LOOP l oop. Априори хорошо определены курсор и переменная строки. И я проверил, и переменная строки содержит строки, запрос возвращает не менее 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 прокомментированы, потому что я отлаживаю код. Но когда они не прокомментированы, ошибка та же самая.

Ответы [ 2 ]

1 голос
/ 23 марта 2020

Ваша процедура имеет некоторые структурные проблемы. Самая насущная проблема - «комментируется оператор открытия и закрытия курсора, потому что я отлаживаю код». Так как открытие в комментариях приводит к сбою FETCH с недопустимым курсором - выборка требует, чтобы курсор был открыт. Вы утверждаете, что на курсоре выдана ошибка FOR l oop. Я думаю, что это было до того, как вы прокомментировали открытое. Курсор FOR выдает открытие для курсора. Который, если курсор открыт, выдает неверный курсор. Вы не можете использовать курсор FOR для открытого курсора. Таким образом, вы либо открываете курсор, обрабатываете эту первую строку (извлекаете), затем закрываете курсор и затем вводите FOR. Не закрывайте курсор после выхода из l oop. У вас есть логическая проблема во вложенной структуре 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» всегда будет возвращать True. Атрибут курсора% rowcount возвращает количество строк, извлеченных из курсора. Атрибут% Found возвращает True, если последняя выборка вернула строку. Поскольку здесь% Rowcount является подчиненным% Found, это означает, что он никогда не сможет вернуть меньше 1.
Еще одно очевидное утверждение - утверждение

IF v2(i-1) = NULL THEN 

У него 2 проблемы. Во-первых, ваша переменная i инициализируется значением 1, поэтому приведенный выше оператор читает v2 (0). Это неверно, значения индекса в pl / sql начинаются с 1. Как только это будет правильно, результирующий оператор никогда не будет True. Вы не можете использовать реляционные операторы с Null; результат, когда вы делаете это всегда Null. Вам нужно "v2 (i) является нулевым". Исправьте эти проблемы, затем, если у вас все еще есть проблемы, отправьте другой вопрос.

1 голос
/ 23 марта 2020

После того, как вы откроете курсор, вам нужно его закрыть.

Кроме того, я изменил ваш курсор, чтобы использовать современное явное соединение.

Я также изменил ваш код в этой части 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;
/

Вот демонстрация, показывающая код работает

...