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を上げた後でも、オラクルのリファレンスを読んだ後、私は少し混乱しています。基本的に、部門番号がnull(0になる)の場合でも、nullの場合はその挿入を行いません。それ以外の場合は挿入します。

それで、コードは正しいですか、それともどのように例外を発生させたり、自分の場合に事前定義された例外を処理したりする必要がありますか?

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;

あなたの一般的なアプローチに関する3つのこと:

  1. どんな例外もLOOPをショートさせます。それ以上の行は処理されません
  2. LOOP 内でコミットしているため、中断したところから簡単に再開できないため、プログラムを再実行するのが難しい場合があります。
  3. ループ内でコミットすると、ORA-1555 または ORA-1002 エラーの問題が発生する可能性があります。これが長時間実行されるクエリの場合は特にそうです。

編集

実際、あなたのコードは手続き型ロジックに関して非常に多くの疑問を投げかけています。私がここに入りたいと思うよりもはるかに。上に挙げた 3 つは一般的な「ベスト プラクティス」の問題ですが、条件付きフローの詳細なロジックはわかりにくいようです。しかし、私はあなたが実装しているビジネスルールを知りません。

于 2010-01-22T10:17:17.993 に答える
2

例外を洗練されていない GOTO ステートメントとして使用するべきではないと思います。コードを構造化する場合は、プロシージャ (およびサブプロシージャ) を使用できます。作業がコード内の 1 か所で行われる場合は、RETURN ステートメントを使用してください。それが理にかなっている場合にのみ、例外をキャッチします。

于 2010-01-22T10:22:23.733 に答える
1

コードにエラーがありますold_emp.num_dep = NULL。機能しません。常にfalseです。

もしそうだったとしたらold_emp.num_dep IS NULL、あなたのコードはあなたの意図に従って機能しないと思います。例外は、INSERTINTOEMP2をバイパスして発生します。

これが私のコードであり、部門が欠落している場合にEMP2に挿入することは実際のエラーではないと判断できるロジックである場合、例外は発生しません。部門が欠落していることが常にわかるため、その情報も失われていません(つまり、部門が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;

ただし、コードにコメントを追加することをお勧めします。上記のようなコードが見つかった場合は、おそらくバグが疑われるからです。

于 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 に答える