じゃあ、PL/pgSQLをもうちょい深く掘って、実際にガンガン使ってみよう!
コードブロック
PL/pgSQLのコードブロックは、言語の基本的なビルディングブロックだよ。いわば、関数やプロシージャとか、いろんな魔法が乗っかってる骨組みみたいなもん。ブロックはロジックの実行、データ処理、エラー制御とか全部ひとつの「コンテナ」でやってくれる。
PL/pgSQLのブロックは構造化されてて、主に3つのパートがある:
DECLARE: 変数の宣言(オプション)。BEGIN ... END: メインの実行ブロック。ここでロジックを実行する。EXCEPTION: エラー処理(オプション)。
たとえば料理のレシピで例えると、材料リストから始まるけど、本当の魔法は調理プロセスで起きるよね。PL/pgSQLで言うと:
DECLARE— 材料リスト(変数)。BEGIN ... END— 混ぜたり焼いたり煮たりする場所。EXCEPTION— もし焦げたらどうするかのプラン。
PL/pgSQLブロックの構文
まずは全体の「骨組み」を見てみよう。あとで肉付け(ベジチーズでもOK!)=具体的なロジックを追加するよ。
DO $$
DECLARE
-- ここで変数を宣言する
student_count INT;
BEGIN
-- ここでロジックを実行する
SELECT COUNT(*) INTO student_count FROM students;
RAISE NOTICE '学生の合計数: %', student_count;
EXCEPTION
-- ここでエラーを処理する
WHEN OTHERS THEN
RAISE NOTICE 'エラーが発生したよ。';
END;
$$;
これをステップごとに分解してみよう。
DECLARE— ここで変数を宣言する。PL/pgSQLはPostgreSQLで使えるほぼ全てのデータ型をサポートしてるから、INTEGERからちょっと変わったJSONBまでOK。変数を宣言するには、名前・型・必要なら初期値を指定するだけ。
例:
DECLARE
student_name TEXT; -- 学生の名前用の変数
course_count INT := 0; -- 初期値を0にする
is_graduated BOOLEAN; -- 論理型の変数
変数は初期化してもいいし(course_countみたいに)、しなくてもOK。
BEGIN ... END— メインの実行ブロック。
このパートがロジックの実行担当。ここで:
- SQLクエリを実行する(
SELECT、INSERTなど)。 - データを操作する。
- 制御構造を使う(
IF、LOOPなど)。 RAISEでデバッグメッセージを出す。
例:
BEGIN
SELECT COUNT(*) INTO student_count FROM students;
IF student_count > 0 THEN
RAISE NOTICE '学生がいるよ!';
ELSE
RAISE NOTICE '学生が見つからなかった。';
END IF;
END;
EXCEPTION— エラー処理(オプション)。
もしブロックの実行中にエラーが起きたら、EXCEPTIONセクションでキャッチして、メッセージを出したり別のコードを実行できる。
例:
BEGIN
SELECT COUNT(*) INTO student_count FROM non_existing_table; -- エラー!
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE 'おっと、何かうまくいかなかった!';
END;
実例:学生のカウント
じゃあ全部まとめて、実際に役立つ例を作ってみよう。studentsテーブルの学生数をカウントして、メッセージを出すPL/pgSQLブロックを書いてみる。
DO $$
DECLARE
total_students INT; -- 学生数を保存する変数
BEGIN
-- 学生数をカウント
SELECT COUNT(*) INTO total_students FROM students;
-- 結果をメッセージで出す
RAISE NOTICE '学生数: %', total_students;
EXCEPTION
-- 例えばテーブルが存在しない場合などのエラーを処理
WHEN OTHERS THEN
RAISE NOTICE '学生数カウント中にエラーが発生したよ。';
END;
$$;
このブロックを実行すると、コンソールにメッセージが出る。例:学生数: 42
変数の使い方のポイント
いくつか大事なポイントを見てみよう:
変数への値の代入。 変数に値を入れるには、SELECT INTOを使う:
SELECT COUNT(*) INTO total_students FROM students;
変数の初期化。 宣言時に値を入れなかったら、デフォルト値はNULLになるよ。
例:
DECLARE
my_var INT; -- 値はNULL
RECORD型の変数。 これはテーブルの行をまるごと入れられる便利な型。例:
DECLARE
student RECORD;
BEGIN
SELECT * INTO student FROM students WHERE id = 1;
RAISE NOTICE '学生名: %, 年齢: %', student.name, student.age;
END;
例:学生のコース数をカウント
今度は実践的な課題:学生が登録してるコース数をカウントして、結果を出そう。
DO $$
DECLARE
student_id INT := 1; -- 学生ID
course_count INT; -- コース数用の変数
BEGIN
-- コース数をカウント
SELECT COUNT(*) INTO course_count
FROM enrollments
WHERE student_id = student_id;
-- メッセージを出す
RAISE NOTICE '学生ID % は % 個のコースに登録してるよ。', student_id, course_count;
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE '学生ID % の処理中にエラーが発生したよ', student_id;
END;
$$;
このブロックは柔軟で、student_idを変えればいろんな学生のコース数をチェックできるよ。
エラーとその回避法
PL/pgSQLに慣れてないと、ホットドッグが電子レンジで暴れてるみたいに感じるかも。でも大丈夫、最初は「ありがち」なミスにぶつかるもん。いくつか例を挙げるね:
変数の宣言忘れ。 DECLAREで変数を宣言し忘れると、「変数が存在しない」ってエラーになる。
NULLを値として使うミス。 変数を宣言しただけで値を入れてないと、デフォルトはNULL。これが予想外の動作を引き起こすことも。例:
IF my_var = NULL THEN -- 動かない!
IS NULLを使おう:
IF my_var IS NULL THEN
EXCEPTIONセクションの使い方ミス。 たまに全部のエラー(WHEN OTHERS)をキャッチして何もしない人がいるけど、これだと本当の問題が隠れちゃう。エラーメッセージはちゃんと出そう:
RAISE NOTICE 'エラー: %', SQLERRM;
GO TO FULL VERSION