2016-10-18 6 views
1

今日はかなり神秘的な問題に遭遇しました。私は次のパラメータを使用して(パラメータの一つが0に等しいとき、私から定義された例外を発生させなければならない)私のSQL関数f_interestrate()を実行したよう:SQL:関数内での例外処理

ORA-06503: PL/SQL: Function returned without value
ORA-06512: at "NOAHBASE.GENERAL_FUNCTIONS", line 73
06503. 00000 - "PL/SQL: Function returned without value"
*Cause: A call to PL/SQL function completed, but no RETURN statement was executed.

*Action: Rewrite PL/SQL function, making sure that it always returns a value of a proper type.

SELECT GENERAL_FUNCTIONS.F_INTERESTRATE(2500000, 0.10, 0) FROM dual; 

は私に次のエラーを与えました

しかし、次のコードサンプルで見られるように、関数は代わりに私が定義した例外ex_invalid_devisorのフォームを呼び出す必要があります。この関数はパッケージ内にネストされていることに注意してください。

FUNCTION f_interestrate(pn_principal NUMBER, pn_interest NUMBER, pn_years NUMBER) RETURN NUMBER IS 
     vn_interestrate NUMBER; 
     ex_invalid_devisor EXCEPTION; 
    BEGIN 
     IF pn_principal = 0 OR 
     pn_interest = 0 OR 
     pn_years = 0 THEN 
      RAISE ex_invalid_devisor; 
     ELSE 
     vn_interestrate := ((pn_interest/pn_principal)-1)/pn_years; 
     RETURN vn_interestrate; 
     END IF; 
    EXCEPTION 
     WHEN ex_invalid_devisor THEN 
     DBMS_OUTPUT.PUT_LINE('Devisor must be bigger then 0'); 
    END; 

何か間違っていますか?

+3

例外が発生した場合には、 'return'句がありません。あなたは、例えばを置く必要があります。 catchブロックに 'nullを返す 'か、例外を再発生させる。あなたの現在のブロックはそれを静かに呑み込む –

+0

あなたの手続きは例外を発生させ、メッセージを出力するためにエラーを処理しますが、この場合戻り値はありません – Aleksej

+1

はい、あなたは何か間違っている:あなたの例外ブロックは何もしません。関数では、エラーを発生させる必要があります(ユーザー定義のエラーの場合は、RAISE_APPLICATION_ERRORを使用して特定のエラー・メッセージを出力できます)。また、DBMS_OUTPUTを使用する必要がある場合は、デバッグ目的でのみ使用する必要があります(IMHO)。プロダクションコードには場所がありません。個人的には、デバッグの他の方法と一緒に行こうと思います。アクションが発生したかどうかを記録する必要がある場合は、代わりにテーブルにログを記録してください。 – Boneist

答えて

2

これはどのように処理する必要があります...私はあなたのコードで 'return -1'を追加しました。 HTH。

create or replace FUNCTION f_interestrate(pn_principal NUMBER, pn_interest NUMBER, pn_years NUMBER) RETURN NUMBER IS 
     vn_interestrate NUMBER; 
     ex_invalid_devisor EXCEPTION; 
    BEGIN 
     IF pn_principal = 0 OR 
     pn_interest = 0 OR 
     pn_years = 0 THEN 
      RAISE ex_invalid_devisor; 
     ELSE 
     vn_interestrate := ((pn_interest/pn_principal)-1)/pn_years; 
     RETURN vn_interestrate; 
     END IF; 
    EXCEPTION 
     WHEN ex_invalid_devisor THEN 
     DBMS_OUTPUT.PUT_LINE('Devisor must be bigger then 0'); 
     return -1; 
    END; 

SQL> select F_INTERESTRATE(2500000, 0.10, 0) FROM dual; 

F_INTERESTRATE(2500000,0.10,0) 
------------------------------ 
          -1 
+0

これは、関数の呼び出し側がエラーとして-1を処理する準備ができている場合にのみ意味があります。あなたは-1が有効な戻り値でないことを確かめなければなりません – Aleksej

+0

それは問題の単なるポイントであり、それが問題を解決することを証明することです。戻り値の値を常に '-1'から何かに変更することができます。ポイントは、値を返さずに関数を持つことができないということです。 -1または-xの値が受け入れられない場合、ゼロ除算例外を処理しない方がよいでしょう。 – pahariayogi

2

PL/SQLはすでに完璧なzero_divide例外を持っているように、私は同じように関数を記述するために誘惑されるだろう:

:あなたは、デフォルトの失敗のメッセージが表示されます

create or replace function f_interestrate 
    (pn_principal number 
    , pn_interest number 
    , pn_years  number) 
    return number 
as 
begin 
    return ((pn_interest/pn_principal) - 1)/pn_years; 
end; 

SQL> select f_interestrate(2500000, 0.10, 0) from dual; 
select f_interestrate(2500000, 0.10, 0) from dual 
     * 
ERROR at line 1: 
ORA-01476: divisor is equal to zero 
ORA-06512: at "XXX.F_INTERESTRATE", line 8 

それとも、実際にいくつかのカスタマイズされた取り扱いが必要な場合は、

create or replace function f_interestrate 
    (pn_principal number 
    , pn_interest number 
    , pn_years  number) 
    return number 
as 
begin 
    return ((pn_interest/pn_principal) - 1)/pn_years; 
exception 
    when zero_divide then 
     [[[ do something here ]]] 
end; 

pn_interestがゼロの場合は、ex_invalid_devisorの例外を発生させることに注意してください。これは除数としては使用されませんが、ここでは微妙なロジックがあります。

(編集:それについて考え、pn_interestがゼロであるならば、多分あなただけに関係なくpn_principalを返却する必要があります。)