1

我有这个程序:

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 EMP2 VALUES (old_emp.bi, old_emp.nome, old_emp.morada, old_emp.data_entrada, old_emp.data_saida, new_ndep);即使在提高dep_inexistente之后,但是在阅读了oracle的参考之后,我还是有点困惑;基本上,当它为空时,我不想插入,否则我想插入,即使部门号为空(我转为 0)。

那么,代码是否正确,或者我应该如何引发我的异常或为我的案例处理预定义的异常?

4

4 回答 4

3

我想做 INSERT INTO EMP2 VALUES (old_emp.bi, old_emp.nome, old_emp.morada, old_emp.data_entrada, old_emp.data_saida, new_ndep);即使在提高 dep_inexistente 之后

诀窍是在插入引发该异常。引发的异常是有效GOTO的语句 - 控制流直接压缩到 EXCEPTIONS 块。在下面的重写中,我使用你的 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. 任何异常都会使 LOOP 短路。不会再处理更多行
  2. 因为您是在 LOOP 中提交的,所以可能很难重新运行程序,因为您将无法轻松地从中断的地方继续。
  3. 在循环内提​​交可能会产生 ORA-1555 或 ORA-1002 错误的问题,特别是如果这是一个长时间运行的查询。

编辑

实际上,您的代码引发了很多关于程序逻辑的问题。远远超过我想进入这里。我在上面列出的三个是一般的“最佳实践”问题,但条件流的详细逻辑看起来很可疑。但是我不知道您正在实施的业务规则。

于 2010-01-22T10:17:17.993 回答
2

我认为不应将异常用作不雅的 GOTO 语句。如果你想构建你的代码,你可以使用过程(和子过程)。如果工作在代码中的某个位置完成,只需使用 RETURN 语句。仅在有意义时才捕获异常。

于 2010-01-22T10:22:23.733 回答
1

您的代码中有一个错误:old_emp.num_dep = NULL不能工作,它总是错误的。

假设它本来是old_emp.num_dep IS NULL,那么我认为您的代码不会按照您的意图工作。绕过 INSERT INTO EMP2 会引发异常。

如果这是我的代码,并且逻辑是这样的,您可以确定在缺少部门的情况下插入 EMP2 不是真正的错误,我不会引发异常。您也不会丢失该信息,因为您总是可以看到缺少部门(即每个部门都为 0 的 emp)

顺便说一句,部门使用 0 是否有特殊原因?为什么不直接使用NULL?显然你已经决定让员工没有部门是可以的,NULL这是一个公平的代表。

如果你坚持认为 emp 错过一个部门实际上是一个错误,但仍然觉得插入 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;

不过,我敦促您在代码中添加一些注释,因为如果我能找到我上面写的代码,我可能会怀疑存在错误。

于 2010-01-22T09:54:18.287 回答
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;

那么你将如何重写它,所以它看起来不那么“不确定”?这有点乱,我不得不承认。不管怎样,至少你给了我非常实用的见解。我想看看一些更好的方法,如果你愿意,我很感兴趣。

于 2010-01-22T10:50:36.637 回答