Продолжить выполнение после обработки исключения - PullRequest
0 голосов
/ 27 мая 2020

Я пишу сценарий для выполнения нескольких уникальных запросов (которые нельзя поместить в al oop). При добавлении обработчика исключений, как только возникает первая ошибка, исключение обрабатывается, но компилятор выходит из блока и завершает программу.

Как мне заставить мою программу обработать исключение и продолжить выполнение следующего запроса ?

Ниже приведен код, над которым я работал:

DECLARE
  NEW_VAR1 VARCHAR2(20000);
  table_does_not_exist exception;
  PRAGMA EXCEPTION_INIT(table_does_not_exist, -942);
BEGIN
  DBMS_output.put_line('Query 1 Execution');
  EXECUTE IMMEDIATE 'BEGIN
    SELECT "defaultpwd" INTO :out1 from sys.user$ where name="APEX_040000" and substr(spare4,3,40)=rawtohex(utl_raw.cast_to_varchar2(sys.dbms_crypto.hash(utl_raw.cast_to_raw("oracle")||hextoraw(substr(spare4,43,20)), 3))) UNION SELECT "defaultpwd" from sys.user$ where name="APEX_040000" and password="EE7785338B8FFE3D";
  END;'
  USING out NEW_VAR1;
  DBMS_output.put_line(NEW_VAR1);

  DBMS_output.put_line('Query 2 Execution');
  EXECUTE IMMEDIATE 'BEGIN
    SELECT "defaultpwd" INTO :out2 from sys.user$ where name="APEX_040000" and substr(spare4,3,40)=rawtohex(utl_raw.cast_to_varchar2(sys.dbms_crypto.hash(utl_raw.cast_to_raw("oracle")||hextoraw(substr(spare4,43,20)), 3))) UNION SELECT "defaultpwd" from sys.user$ where name="APEX_040000" and password="EE7785338B8FFE3D";
  END;'
  USING out NEW_VAR1;
  DBMS_output.put_line(NEW_VAR1);
EXCEPTION
  WHEN table_does_not_exist THEN
    DBMS_output.put_line('Table does not exist!!');
  WHEN others then
    DBMS_output.put_line('Error!!');
END;

Желаемый результат в этом случае будет:

Query 1 Execution
Error!!
Query 2 Execution
Error!!

Фактический результат:

Query 1 Execution
Error!!

Я открыт для альтернативных способов выполнения нескольких отдельных запросов, если вышеупомянутый код неэффективен.

Ответы [ 3 ]

2 голосов
/ 27 мая 2020

Я думаю, вам нужно иметь разные блоки исключений для каждого запроса. Примерно так:

    DECLARE
      NEW_VAR1 VARCHAR2(20000);
      table_does_not_exist exception;
      PRAGMA EXCEPTION_INIT(table_does_not_exist, -942);
    BEGIN
      BEGIN
          DBMS_output.put_line('Query 1 Execution');
          EXECUTE IMMEDIATE 'BEGIN
            SELECT "defaultpwd" INTO :out1 from sys.user$ where name="APEX_040000" and    substr(spare4,3,40)=rawtohex(utl_raw.cast_to_varchar2(sys.dbms_crypto.hash(utl_raw.cast_to_raw("oracle")||hextoraw(substr(spare4,43,20)), 3))) UNION SELECT "defaultpwd" from sys.user$ where name="APEX_040000" and password="EE7785338B8FFE3D";
          END;'
          USING out NEW_VAR1;
          DBMS_output.put_line(NEW_VAR1);
      EXCEPTION
          WHEN table_does_not_exist THEN
              DBMS_output.put_line('Table does not exist!!');
          WHEN others then
              DBMS_output.put_line('Error!!');
      END;

      BEGIN
          DBMS_output.put_line('Query 2 Execution');
          EXECUTE IMMEDIATE 'BEGIN
            SELECT "defaultpwd" INTO :out2 from sys.user$ where name="APEX_040000" and substr(spare4,3,40)=rawtohex(utl_raw.cast_to_varchar2(sys.dbms_crypto.hash(utl_raw.cast_to_raw("oracle")||hextoraw(substr(spare4,43,20)), 3))) UNION SELECT "defaultpwd" from sys.user$ where name="APEX_040000" and password="EE7785338B8FFE3D";
          END;'
          USING out NEW_VAR1;
          DBMS_output.put_line(NEW_VAR1);
      EXCEPTION
          WHEN table_does_not_exist THEN
              DBMS_output.put_line('Table does not exist!!');
          WHEN others then
              DBMS_output.put_line('Error!!');
      END;
    END;
1 голос
/ 27 мая 2020

В принципе, вы должны сделать это так:

DECLARE
  NEW_VAR1 VARCHAR2(20000);
  table_does_not_exist exception;
  PRAGMA EXCEPTION_INIT(table_does_not_exist, -942);
BEGIN

BEGIN
  DBMS_output.put_line('Query 1 Execution');
  EXECUTE IMMEDIATE 'BEGIN
    SELECT "defaultpwd" INTO :out1 from sys.user$ where name="APEX_040000" and substr(spare4,3,40)=rawtohex(utl_raw.cast_to_varchar2(sys.dbms_crypto.hash(utl_raw.cast_to_raw("oracle")||hextoraw(substr(spare4,43,20)), 3))) UNION SELECT "defaultpwd" from sys.user$ where name="APEX_040000" and password="EE7785338B8FFE3D";
  END;'
  USING out NEW_VAR1;
  DBMS_output.put_line(NEW_VAR1);
EXCEPTION
  WHEN table_does_not_exist THEN
    DBMS_output.put_line('Table does not exist!!');
  WHEN others then
    DBMS_output.put_line('Error!!');
END;

BEGIN
  DBMS_output.put_line('Query 2 Execution');
  EXECUTE IMMEDIATE 'BEGIN
    SELECT "defaultpwd" INTO :out2 from sys.user$ where name="APEX_040000" and substr(spare4,3,40)=rawtohex(utl_raw.cast_to_varchar2(sys.dbms_crypto.hash(utl_raw.cast_to_raw("oracle")||hextoraw(substr(spare4,43,20)), 3))) UNION SELECT "defaultpwd" from sys.user$ where name="APEX_040000" and password="EE7785338B8FFE3D";
  END;'
  USING out NEW_VAR1;
  DBMS_output.put_line(NEW_VAR1);
EXCEPTION
  WHEN table_does_not_exist THEN
    DBMS_output.put_line('Table does not exist!!');
  WHEN others then
    DBMS_output.put_line('Error!!');
END;

END;

Или поместите его в al oop:

BEGIN

FOR i IN 1..2 LOOP
  BEGIN
    DBMS_output.put_line('Query '||i||' Execution');
    EXECUTE IMMEDIATE ...

  EXCEPTION
    WHEN table_does_not_exist THEN
      DBMS_output.put_line('Table does not exist!!');
    WHEN others then
      DBMS_output.put_line('Error!!');
  END;
END LOOP;

END;

Однако в вашем коде есть несколько ошибок / fl aws:

  • Почему вы дважды выполняете один и тот же запрос?
  • EXECUTE IMMEDIATE требует, чтобы была возвращена ровно одна строка. Из-за UNION это маловероятно.
  • Код должен быть похож на EXECUTE IMMEDIATE 'SELECT ... FROM ...' INTO NEW_VAR1;
  • Я не думаю, что в таблице sys.user$ есть столбец defaultpwd (в нижнем регистре)
  • вы должны использовать WHEN others then DBMS_output.put_line('Error!!' || SQLERRM);, чтобы увидеть фактическую ошибку, иначе вы ее скроете. Это еще хуже, поскольку вы новичок в SQL
  • Какова цель вашего запроса, для меня это не имеет большого смысла. Если вам нравится сравнивать с PASSWORD make simple = или <>
  • Даже если ваш запрос будет работать, нет причин для динамического c SQL. Используйте простой SELECT ... INTO NEW_VAR1 FROM .... EXECUTE IMMEDIATE не требуется.
0 голосов
/ 27 мая 2020

Есть какая-то особая причина для Dynami c SQL? В выполняемых вами запросах нет ничего Dynami c.

Что хуже , так это то, что эти выборки используют UNION, что означает, что они, возможно, вернут две или более строк в скалярную переменную, и это не сработает.

Кроме того, вы неправильно использовали предложение INTO.

Это похоже на то, что вы делаете сейчас (пример основан на схеме Скотта):

SQL> declare
  2    l_result varchar2(20);
  3  begin
  4    execute immediate
  5    q'[select deptno into :out1
  6      from emp
  7      where ename = 'SCOTT'
  8     union
  9     select deptno into :out2
 10       from dept
 11       where dname = 'ACCOUNTING']'
 12    using out l_result;
 13
 14    dbms_output.put_line(l_result);
 15  end;
 16  /
declare
*
ERROR at line 1:
ORA-01744: inappropriate INTO
ORA-06512: at line 4


SQL>

Если вы исправите это, вы получите хуже вещь: too_many_rows, поскольку вы возвращаете 2 строки в одну varchar2 переменную:

SQL> declare
  2    l_result varchar2(20);
  3  begin
  4    execute immediate
  5    q'[select deptno
  6      from emp
  7      where ename = 'SCOTT'
  8     union
  9     select deptno
 10       from dept
 11       where dname = 'ACCOUNTING']'
 12    into l_result;
 13
 14    dbms_output.put_line(l_result);
 15  end;
 16  /
declare
*
ERROR at line 1:
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 4

Поскольку в нем нет ничего динамического c , переключитесь на чистый select (конечно, снова вернет too_many_rows):

SQL> declare
  2    l_result varchar2(20);
  3  begin
  4    select deptno
  5      into l_result
  6      from (select deptno
  7              from emp
  8              where ename = 'SCOTT'
  9            union
 10            select deptno
 11              from dept
 12              where dname = 'ACCOUNTING'
 13           );
 14
 15    dbms_output.put_line(l_result);
 16  end;
 17  /
declare
*
ERROR at line 1:
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 4

Наконец, используйте соответствующую переменную, массив:

SQL> declare
  2    l_result sys.odcivarchar2list;
  3  begin
  4    select deptno
  5      bulk collect into l_result
  6      from (select deptno
  7              from emp
  8              where ename = 'SCOTT'
  9            union
 10            select deptno
 11              from dept
 12              where dname = 'ACCOUNTING'
 13           );
 14
 15    for i in l_result.first .. l_result.last loop
 16      dbms_output.put_line(l_result(i));
 17    end loop;
 18  end;
 19  /
10
20

PL/SQL procedure successfully completed.

SQL>

As ошибок, с которыми вы сталкиваетесь: как вам уже было сказано, вам нужно заключить каждый оператор в отдельный блок begin-exception-end. Что-то вроде этого упрощенного примера («упрощенный» означает, что вы должны правильно обрабатывать исключения. Не используйте WHEN OTHERS только потому, что они существуют; вы бы предпочли позволить ошибке произойти, распознать ее и обработать правильно):

declare
  l_result sys.odcivarchar2list;
begin
  -- start of the first inner begin-exception-end block
  begin
    select deptno
      bulk collect into l_result
      from (select deptno
              from emp
              where ename = 'SCOTT'
            union 
            select deptno
              from dept
              where dname = 'ACCOUNTING'
           );

    for i in l_result.first .. l_result.last loop
      dbms_output.put_line(l_result(i));
    end loop;  
  exception
    when others then
      dbms_output.put_Line('handle it');
  end;
  -- end of the first inner begin-exception-end block

  -- start of the second inner begin-exception-end block
  begin
    null;
  exception
    when others then null;
  end;
  -- end of the second inner begin-exception-end block
end;
/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...