2010-01-22 2 views
1

У меня есть эта процедура:объем рейза исключения, обработки собственных исключений в коде PLSQL

create or replace PROCEDURE CONVERTE 
IS 
    CURSOR oldemployees IS 
     SELECT * 
     FROM emp1 
     WHERE data_saida= NULL; 

    new_ndep emp1.num_dep%type; 
    bi_inexistente EXCEPTION; 
    dep_inexistente EXCEPTION; 
    employeeNr emp1.num_empregado%type; 

BEGIN 
    FOR old_emp IN oldemployees 
    LOOP 
    employeeNr:= old_emp.num_empregado; 
     if (old_emp.bi = NULL) then 
     raise bi_inexistente; 
    else 
     IF (old_emp.num_dep>20) THEN 
       SELECT ndep_novo INTO new_ndep FROM Converte_dep WHERE ndep_antigo= old_emp.num_dep; 
     elsif (old_emp.num_dep = NULL) then 
      new_ndep:= 0; 
      raise dep_inexistente;  
     end if; 
     INSERT INTO EMP2 VALUES (old_emp.bi, old_emp.nome, old_emp.morada, old_emp.data_entrada, old_emp.data_saida, new_ndep); 
     COMMIT; 
    end if; 
    end loop; 

EXCEPTION 
when bi_inexistente then 
    INSERT INTO ERROS VALUES(employeeNr, 'BI Inexistente'); 
    COMMIT; 

when dep_inexistente then 
    INSERT INTO ERROS VALUES(employeeNr, 'Departamento Inexistente'); 
    COMMIT; 
end; 

Я хочу сделать INSERT INTO етр2 VALUES (old_emp.bi, old_emp.nome, old_emp.morada, old_emp. data_entrada, old_emp.data_saida, new_ndep); даже после поднятия dep_inexistente, но после прочтения оракула, я немного смущен; В принципе, когда он равен нулю, я не хочу делать эту вставку, иначе я хочу вставить, даже если номер отдела равен нулю (к которому я обращаюсь 0).

Итак, это правильный код или как мне поднять мои исключения или обработать предопределенные исключения для моего случая?

ответ

2

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

1

В вашем коде есть ошибка: old_emp.num_dep = NULL не может работать, это всегда неверно.

Предположим, что это было бы old_emp.num_dep IS NULL, тогда я думаю, что ваш код не будет работать в соответствии с вашим назначением. Исключение будет поднято в обход INSERT INTO EMP2.

Если это был мой код, и логика такова, что вы можете решить, что это не настоящая ошибка для вставки в EMP2 в случае отсутствия отдела, я бы не стал создавать исключение. Вы также не теряете эту информацию, так как вы всегда можете видеть, что отсутствовали отделы (а именно для каждой emp с 0 как отдел)

Кстати, есть ли какая-то конкретная причина для использования 0 для отдела? Почему бы просто не использовать NULL? Видимо, вы решили, что у сотрудников нет отдела, NULL - это справедливое представление об этом.

Если вы настаиваете, что это на самом деле ошибка для ого пропустить отдел, но все еще чувствуете, что это нормально, чтобы вставить EMP в любом случае, я бы тебе это так:

IF ... THEN 
    ... -- ok 
END IF; 
INSERT INTO EMP2 VALUES (
    old_emp.bi, old_emp.nome, old_emp.morada, old_emp.data_entrada, old_emp.data_saida, 
    NVL(new_ndep, 0) 
); 
IF new_ndep IS NULL THEN 
    raise dep_inexistente; 
END IF; 

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

3

Я хочу сделать INSERT INTO етр2 ЗНАЧЕНИЯ (old_emp.bi, old_emp.nome, old_emp.morada, old_emp.data_entrada, old_emp.data_saida, new_ndep); даже после того, как повышение dep_inexistente

Хитрость заключается в том, чтобы поднять это исключение после делать вставки. Исключенные исключения - это фактически GOTO заявления - поток управляющих молний прямо в блок ИСКЛЮЧЕНИЯ. В следующем переписании я использовал вашу настройку new_dep в качестве сигнала для повышения исключения. Возможно, вам известно о какой-либо другой бизнес-логике, которая делает недействительным такой подход (т. Е. Существует некоторая законная причина, по которой запись имеет нулевой уровень отдела). В этом случае вам нужно будет установить флаг вместо этого.

create or replace PROCEDURE CONVERTE IS 
    CURSOR oldemployees IS 
     SELECT * 
     FROM emp1 
     WHERE data_saida= NULL; 
    new_ndep emp1.num_dep%type; 
    bi_inexistente EXCEPTION; 
    dep_inexistente EXCEPTION; 
    employeeNr emp1.num_empregado%type; 
BEGIN 
    FOR old_emp IN oldemployees 
    LOOP 
     employeeNr:= old_emp.num_empregado; 
     if (old_emp.bi is NULL) then 
      raise bi_inexistente; 
     else 
      if (old_emp.num_dep>20) THEN 
       SELECT ndep_novo INTO new_ndep FROM Converte_dep WHERE ndep_antigo= old_emp.num_dep; 
      elsif (old_emp.num_dep is NULL) then 
       new_ndep:= 0; 
      end if; 
      INSERT INTO EMP2 VALUES (old_emp.bi, old_emp.nome, old_emp.morada, old_emp.data_entrada, old_emp.data_saida, new_ndep); 
      COMMIT; 
      if new_ndep = 0 then 
       raise dep_inexistente;  
      end if; 
     end if; 
    end loop; 
EXCEPTION 
    when bi_inexistente then 
     INSERT INTO ERROS VALUES(employeeNr, 'BI Inexistente'); 
     COMMIT; 
    when dep_inexistente then 
     INSERT INTO ERROS VALUES(employeeNr, 'Departamento Inexistente'); 
     COMMIT; 
end; 

Три вещи, о вашем общем подходе:

  1. Любое исключение короткого замыкания цикла. Никакие дальнейшие строки не будут обработаны
  2. Поскольку вы совершаете в пределах LOOP, может быть сложно перезапустить программу, потому что вы не сможете легко получить пикап с того места, где вы остановились.
  3. Завершение внутри цикла может создавать проблемы с ошибками ORA-1555 или ORA-1002, особенно если это длинный запрос.

редактировать

На самом деле ваш код вызывает очень много вопросов относительно процессуальной логики. Гораздо больше, чем хотелось бы здесь. Три из перечисленных выше - это общие проблемы «лучшей практики», но детальная логика условного потока выглядит iffy. Но тогда я не знаю, какие бизнес-правила вы реализуете.

0

Итак, если я держу исключения было бы так:

create or replace PROCEDURE CONVERTE IS 
     CURSOR oldemployees IS 
      SELECT * 
      FROM emp1 
      WHERE data_saida= NULL; 
     new_ndep emp1.num_dep%type; 
     bi_inexistente EXCEPTION; 
     dep_inexistente EXCEPTION; 
     employeeNr emp1.num_empregado%type; 
    BEGIN 
     FOR old_emp IN oldemployees 
     LOOP 
      employeeNr:= old_emp.num_empregado; 
      if (old_emp.bi is NULL) then 
       raise bi_inexistente; 
      else 
       if (old_emp.num_dep>20) THEN 
        SELECT ndep_novo INTO new_ndep FROM Converte_dep WHERE ndep_antigo= old_emp.num_dep; 
       else 
        INSERT INTO EMP2 VALUES (old_emp.bi, old_emp.nome, old_emp.morada, old_emp.data_entrada, old_emp.data_saida,nvl(old_emp.num_dep,0)); 
       end if; 
       if new_ndep is NULL then 
        raise dep_inexistente;  
       end if; 
      end if; 
     end loop; 
    EXCEPTION 
     when bi_inexistente then 
      INSERT INTO ERROS VALUES(employeeNr, 'BI Inexistente'); 
      COMMIT; 
     when dep_inexistente then 
      INSERT INTO ERROS VALUES(employeeNr, 'Departamento Inexistente'); 
      COMMIT; 
    end; 

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

create or replace 
    PROCEDURE CONVERTE2 IS 
     CURSOR oldemployees IS 
      SELECT * 
      FROM emp1 
      WHERE data_saida= NULL; 
     new_ndep emp1.num_dep%type; 
     bi_inexistente EXCEPTION; 
     dep_inexistente EXCEPTION; 
     employeeNr emp1.num_empregado%type; 
     v_error_code NUMBER:=0; 
     v_error_message VARCHAR2(255); 

    BEGIN 
     FOR old_emp IN oldemployees 
     LOOP 
      employeeNr:= old_emp.num_empregado; 
      if (old_emp.bi is NULL) then 
       INSERT INTO ERROS VALUES(employeeNr, 'BI Inexistente'); 
      else 
       if (old_emp.num_dep>20) THEN 
        SELECT ndep_novo INTO new_ndep FROM Converte_dep WHERE ndep_antigo= old_emp.num_dep; 
       else 
        INSERT INTO EMP2 VALUES (old_emp.bi, old_emp.nome, old_emp.morada, old_emp.data_entrada, old_emp.data_saida,nvl(old_emp.num_dep,0)); 
       end if; 
       if new_ndep is NULL then 
        INSERT INTO ERROS VALUES(employeeNr, 'Departamento Inexistente'); 
       end if; 
      end if; 
     end loop; 
     COMMIT; 

    EXCEPTION 
     When others Then 
     ROLLBACK; 
     /*eventually log something into erro table*/ 

    end; 

Как бы вы переписали его, так что это выглядит не так «iffy»? Должен признаться, это немного грязно. Во всяком случае, по крайней мере, вы дали мне очень правдивые идеи. Я бы хотел, чтобы вы были лучше, если хотите, мне интересно.

Смежные вопросы