たまにループは順調に進むけど、「あ、ここで止めたい!」ってタイミングが出てくるよね。ラッキーなことに、PL/pgSQLにはそれを簡単にコントロールできる便利なツールがあるんだ。
EXITでループを中断する
ループが最後まで行く前に終わらせたい時があるよね。例えば、欲しい値を見つけた時とか、エラーを検知した時、ある条件でイテレーションを終わらせたい時とか。そんな時に使うのがEXIT。
EXITはループに「もう十分やったから、ここで終わろうぜ」って伝える感じ。
EXITのシンタックスはめっちゃシンプル:
EXIT WHEN 条件;
ここでWHENは、どんな条件でループを終わらせるかを指定するよ。条件を書かないと、EXITはその場でループを即終了させる。
例:指定した値を見つけたらループを終わらせる
例えば、学生番号のカラムがあって、特定のIDの学生を探したいとする。見つけたらループを終わらせたいよね。
DO $$
DECLARE
student_id INT;
BEGIN
FOR student_id IN 1..100 LOOP
RAISE NOTICE '学生IDをチェック中: %', student_id;
-- 欲しい学生を見つけたらループを終了
IF student_id = 42 THEN
RAISE NOTICE 'ID 42の学生が見つかった!';
EXIT;
END IF;
END LOOP;
END $$;
この例では、1から100までの数字をループして「学生」をチェックしてる。ID42を見つけたら、メッセージを出してループを終了するよ。
CONTINUEでイテレーションをスキップする
ループの中で特定のイテレーションだけスキップして、次のイテレーションに進みたい時もあるよね。いらないデータを無視したい時や、特定の条件だけ飛ばしたい時に便利。
CONTINUEは「この条件はパス、次いこ!」って感じ。
CONTINUEはEXITと似てるけど、ループ自体を終わらせるんじゃなくて、今のイテレーションだけスキップする:
CONTINUE WHEN 条件;
条件が成立したら、そのイテレーションは終わって、次のイテレーションに進むよ。
例:偶数をスキップする
この例では、1から10までの数字をループして、偶数はスキップして奇数だけ出力するよ。
DO $$
DECLARE
num INT;
BEGIN
FOR num IN 1..10 LOOP
-- 偶数はスキップ
IF num % 2 = 0 THEN
CONTINUE;
END IF;
RAISE NOTICE '奇数: %', num;
END LOOP;
END $$;
ここでCONTINUEはnum % 2 = 0(つまり偶数)の時にイテレーションをスキップする。結果としてログには奇数だけが出力されるよ。
EXITとCONTINUEの組み合わせ
EXITとCONTINUEは一緒に使うこともできて、ループをもっと柔軟にコントロールできる。例えば、いらないイテレーションはCONTINUEでスキップして、大事なものを見つけたらEXITでループを終わらせるとか。
例えば、3の倍数は全部スキップして、15になったらループを終了する例を見てみよう。
DO $$
DECLARE
num INT;
BEGIN
FOR num IN 1..20 LOOP
-- 3の倍数はスキップ
IF num % 3 = 0 THEN
CONTINUE;
END IF;
-- 15になったらループ終了
IF num = 15 THEN
RAISE NOTICE '番号%でストップ', num;
EXIT;
END IF;
RAISE NOTICE '現在の番号: %', num;
END LOOP;
END $$;
このループの流れはこんな感じ:
- 3の倍数はスキップ(
CONTINUE)。 - 15になったらループ終了(
EXIT)。 - それ以外の数字は出力される。
応用例:不正なデータをスキップ&クリティカルエラーで終了
今度はもうちょっとリアルな課題を考えてみよう。学生リストを処理して、データをチェックする。不正なレコードはスキップして、「クリティカルエラー」があったら処理をやめる、みたいな感じ。
DO $$
DECLARE
student RECORD;
BEGIN
FOR student IN
SELECT * FROM students
LOOP
-- 名前がない学生はスキップ
IF student.name IS NULL THEN
RAISE NOTICE 'ID%の学生をスキップ: 名前がない', student.id;
CONTINUE;
END IF;
-- クリティカルエラーならループ終了
IF student.status = 'ERROR' THEN
RAISE EXCEPTION 'ID%の学生でクリティカルエラー', student.id;
EXIT; -- この行は実際には不要、RAISE EXCEPTIONで実行が終わるから。
END IF;
-- レコードの処理
RAISE NOTICE '学生を処理中: %', student.name;
END LOOP;
END $$;
この例では、CONTINUEで名前がない学生をスキップして、EXIT(とRAISE EXCEPTION)で重大なエラーがあったらループを終わらせてる。
実践アドバイス&よくあるミス
条件のロジックに注意しよう。 EXIT WHENやCONTINUE WHENの条件式を間違えると、思わぬ動作になることがある。例えば、ループが早く終わりすぎたり、大事なデータをスキップしちゃったり。
CONTINUEの使いすぎに注意。 コードがCONTINUEだらけになってたら、ループのロジックを見直した方がいいかも。もっとシンプルにできるかもよ。
EXITとRETURNを混同しないで。 EXITは今のループだけを終わらせるけど、RETURNは関数全体の実行を終わらせる。
無限ループには気をつけて。 LOOPで終了条件を書かずにEXITを忘れると、ループが永遠に回り続けることもあるよ。
GO TO FULL VERSION