CodeGym /コース /SQL SELF /エラー処理: RAISE EXCEPTION

エラー処理: RAISE EXCEPTION

SQL SELF
レベル 52 , レッスン 0
使用可能

例えば、学生の平均点を計算する関数を書いてるとしよう。もし点数がなかったら(つまりゼロで割ろうとしたら)どうなる?そんなコードを本番に出したら、思わぬエラーがすぐにやってくるよね。PL/pgSQLには、こういうエラーをしっかり処理できる強力なツールがあるから、コードが頑丈で安全、しかも扱いやすくなるんだ。

PL/pgSQLのエラー処理でできること:

  1. 何がダメだったのか説明するメッセージを出せる。
  2. 致命的なエラーのときはコードの実行を止められる。
  3. 問題をログに残して、あとで分析できる。

PL/pgSQLの主なメッセージレベル

PL/pgSQLにはいくつかのメッセージレベルがあって、開発者が問題を効率よく見つけて直せるようになってる。こんな感じ:

  • NOTICE: 情報メッセージを出す。デバッグ用に使うよ。
  • WARNING: プログラムの実行は止まらないけど、何か問題がありそうなときの通知。
  • EXCEPTION: プログラムの実行を止める致命的なエラー(呼び出し元に制御が戻る)。

PL/pgSQLのメッセージレベル一覧

メッセージレベル 説明
NOTICE 情報やデバッグ用メッセージ。実行には影響しない
WARNING 問題がありそうなときの警告。ヒントとして使う
EXCEPTION プログラムの実行を止める重大なエラー

RAISEコマンドの構文

メッセージを出したりエラーを処理したりするにはRAISE文を使うよ。基本の構文はこれ:

RAISE <メッセージレベル> 'メッセージテキスト' [, 変数...];
  • <メッセージレベル>NOTICE, WARNING, EXCEPTIONのどれか。
  • 'メッセージテキスト' — 問題の説明。
  • [変数...] — メッセージテキストに埋め込む追加の値。

例1: RAISE NOTICEの使い方

関数の中で何が起きてるか知りたいときってあるよね。例えばループのデバッグ:

DO $$
BEGIN
    FOR i IN 1..5 LOOP
        RAISE NOTICE '今のiの値: %', i;
    END LOOP;
END
$$;

結果: コンソールに今のiの値: 1今のiの値: 2…5まで出力されるよ。

例2: RAISE EXCEPTIONの使い方

今度は、特定の条件でエラーを出して関数を終了させたい場合:

DO $$
BEGIN
    IF 1 = 1 THEN
        RAISE EXCEPTION '何かおかしいぞ!';
    END IF;
END
$$;

結果: 実行が止まって、エラーメッセージがコンソールに出る。

RAISEでパラメータを使う

パラメータを使えば、メッセージテキストをカスタマイズできる。%のプレースホルダーを使うよ:

例3: RAISEに変数を埋め込む

DO $$
DECLARE
    student_name TEXT := 'イワン';
    average_score NUMERIC := NULL;
BEGIN
    IF average_score IS NULL THEN
        RAISE EXCEPTION '学生 % の平均点がないよ!', student_name;
    END IF;
END
$$;

結果: 学生 イワン の平均点がないよ!というメッセージ。

こんな感じで、%student_nameの値に置き換わるから、メッセージが分かりやすくなるね。

カスタムエラーの生成

エラーって、トラブルだけじゃなくて、わざと作ってコードを守るためにも使うんだ。

例4: 入力値のチェック

数値の入力値をチェックして、マイナスだったらエラーを出す関数を書いてみよう:

CREATE OR REPLACE FUNCTION check_positive(value NUMERIC)
RETURNS TEXT AS $$
BEGIN
    IF value < 0 THEN
        RAISE EXCEPTION '数値 % はマイナスだよ!', value;
    END IF;
    RETURN '数値はOK。';
END;
$$ LANGUAGE plpgsql;

この関数をテストしてみる:

SELECT check_positive(-5);

結果: 数値 -5 はマイナスだよ!というエラー。

もしプラスの値を渡したら:

SELECT check_positive(10);

結果: 数値はOK。

コンテキストでのエラー処理

エラーを発生させるだけじゃなくて、状況に応じて処理できたらもっといいよね。そのためにBEGIN ... EXCEPTIONブロックを使うんだ。

エラー処理の構造

BEGIN
    -- メインのコード
EXCEPTION
    WHEN エラータイプ THEN
        -- エラーのときの処理
    WHEN 別のエラー THEN
        -- 別のエラーのときの処理
    WHEN OTHERS THEN
        -- その他すべてのエラーの処理
END;

各パーツの意味:

  • EXCEPTION — エラー処理ブロックの始まりを示すキーワード。
  • WHEN — 例えばunique_violationdivision_by_zeroみたいに、特定のエラータイプを指定できる。
  • OTHERSWHENで指定してないすべてのエラーを処理するのに使う。

例5: ゼロ除算のエラー処理

簡単な割り算関数でエラー処理を見てみよう:

CREATE OR REPLACE FUNCTION safe_divide(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
    -- 割り算を試す
    RETURN a / b;
EXCEPTION
    WHEN division_by_zero THEN
        RAISE WARNING 'ゼロで割ろうとしたよ。NULLを返すね。';
        RETURN NULL;
END;
$$ LANGUAGE plpgsql;

この関数をテスト:

SELECT safe_divide(10, 2);  -- 期待される結果: 5
SELECT safe_divide(10, 0);  -- 期待される結果: NULLとコンソールに警告

RAISEを使うときのよくあるミス

メッセージレベルの指定忘れ。 レベルを指定しないと、PostgreSQLがエラーを出すよ。

ダメな例:

RAISE 'レベルなしのメッセージ';

正しい例:

RAISE NOTICE 'NOTICEレベルのメッセージ';

パラメータの数が合ってない。 %を使うなら、ちゃんと必要な数だけ変数を渡そう。

ダメな例:

RAISE NOTICE 'パラメータ付きの例 %';

正しい例:

RAISE NOTICE 'パラメータ付きの例 %', '値';

やりすぎ。 RAISE EXCEPTIONを多用しすぎると、大事な処理まで止まっちゃう。使いどころは考えてね。

お役立ちヒント

  1. WHEN OTHERSブロックには注意。 できるだけ具体的なエラーを指定して、他のエラーを間違ってキャッチしないようにしよう。
  2. RAISEはデバッグにも使える。 エラーは絶対に放置しないでね。
  3. パフォーマンスも忘れずに。 エラー処理は特に大きなプロシージャだとコストがかかることもあるよ。

ここまでちゃんとできれば、君のプロシージャはどんな予期せぬトラブルにも耐えられるはず。PMもきっと君を誇りに思うよ!

コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION