RAISE NOTICE、RETURN QUERYのオペレーター
プログラミングで大事なのは2つ:何が起きてるか理解すること(特に思った通りに動かない時!)、そして役立つデータを返すこと。PL/pgSQLだとサーバーサイドで動くから、デバッグはそんなに簡単じゃない。そこで便利なのが組み込みツール:
RAISE NOTICEは、関数実行中にメッセージを表示する方法だよ。JavaScriptのconsole.logやPythonのprintみたいな感じ。変数の値や今どこまで進んだかを見せたり、未来の自分への「挨拶」を残したりできる。
RETURN QUERYは、テーブル全体や複雑なクエリの結果みたいなデータセットを返す方法。これでPL/pgSQL関数も本格的なSQLクエリっぽくなるよ。
RAISE NOTICEコマンド
RAISE NOTICEは、関数実行中に画面にメッセージを出せる。フォーマットはこんな感じ:
RAISE NOTICE 'メッセージ: %', 値;
%はCのprintfみたいな変数のプレースホルダー。- メッセージの後ろに、挿入したい変数を並べる。
使い方の例
例えば、いろんなグループの学生数を数える関数を書いてるとする。途中経過を見て、ちゃんと動いてるか確認したいよね。
CREATE OR REPLACE FUNCTION count_students_in_groups() RETURNS VOID AS $$
DECLARE
group_name TEXT;
student_count INT;
BEGIN
FOR group_name IN SELECT DISTINCT group_name FROM students LOOP
SELECT COUNT(*) INTO student_count
FROM students WHERE group_name = group_name;
-- 結果を表示
RAISE NOTICE 'グループ: %, 学生数: %', group_name, student_count;
END LOOP;
END;
$$ LANGUAGE plpgsql;
この関数を呼び出すと:
SELECT count_students_in_groups();
ログにこんなメッセージが出るよ:
NOTICE: グループ: 数学, 学生数: 30
NOTICE: グループ: 哲学, 学生数: 25
NOTICE: グループ: 生物学, 学生数: 18
この関数は何も返さない(RETURNS VOIDで作ってる)が、RAISE NOTICEでループの進み具合が分かる。
RAISEの便利なトリック
NOTICE以外にも、いろんなレベルのメッセージが使える:
RAISE DEBUG— 追加情報用(ログレベルDEBUGの時だけ表示)。RAISE INFO— 一般的な情報。RAISE WARNING— 警告。RAISE EXCEPTION— エラーを発生させる(これは後でやる)。
デバッグにはNOTICEかDEBUGがオススメ。実行を止めずに使えるから便利だよ。
RETURN QUERYコマンド:データをプロっぽく返そう
RETURN QUERYはPL/pgSQLで複数行のデータを返す時に使う。SQLクエリの結果をそのまま関数から返せる。シンタックスは:
RETURN QUERY <SQLクエリ>;
複数のクエリも組み合わせられる:
RETURN QUERY <SQLクエリ1>;
RETURN QUERY <SQLクエリ2>;
例1:RETURN QUERY付き関数
指定したグループの学生リストを返す関数を書いてみよう。
CREATE OR REPLACE FUNCTION get_students_by_group(group_name TEXT)
RETURNS TABLE(id INT, name TEXT) AS $$
BEGIN
RETURN QUERY
SELECT id, name
FROM students
WHERE group_name = group_name;
END;
$$ LANGUAGE plpgsql;
この関数を呼び出す:
SELECT * FROM get_students_by_group('数学');
まずstudentsテーブルを作って、データを入れてみよう:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
group_name TEXT NOT NULL
);
INSERT INTO students (name, group_name) VALUES
('Otto Song', '物理'),
('Alex Lin', '数学'),
('Anna Vel', '数学'),
('Maria Chi', '歴史');
結果:
| id | name |
|---|---|
| 2 | Alex Lin |
| 3 | Anna Vel |
見ての通り、この関数は普通のSQLクエリみたいに動くよ。
例2:複数クエリの合体
もし複数テーブルからデータをまとめて返したい場合は?例えば、学生と彼らが登録してるコースのリストを返そう。
CREATE OR REPLACE FUNCTION get_students_and_courses()
RETURNS TABLE(student_name TEXT, course_name TEXT) AS $$
BEGIN
RETURN QUERY
SELECT s.name, c.name
FROM students s
JOIN enrollments e ON s.id = e.student_id
JOIN courses c ON e.course_id = c.id;
END;
$$ LANGUAGE plpgsql;
まずstudents、courses、enrollmentsの3つのテーブルを作って、データを入れる:
-- 学生テーブル
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- コーステーブル
CREATE TABLE courses (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- コース登録テーブル(中間テーブル)
CREATE TABLE enrollments (
student_id INT REFERENCES students(id),
course_id INT REFERENCES courses(id)
);
-- 学生を追加
INSERT INTO students (name) VALUES
('Otto Song'),
('Alex Lin'),
('Anna Vel'),
('Maria Chi');
-- コースを追加
INSERT INTO courses (name) VALUES
('数学'),
('物理'),
('歴史');
-- コース登録を追加
INSERT INTO enrollments (student_id, course_id) VALUES
(1, 2), -- Otto -> 物理
(2, 1), -- Alex -> 数学
(3, 1), -- Anna -> 数学
(4, 3); -- Maria -> 歴史
この関数を呼ぶと:
SELECT * FROM get_students_and_courses();
こんな結果になる:
| student_name | course_name |
|---|---|
| Otto Song | 物理 |
| Alex Lin | 数学 |
| Anna Vel | 数学 |
| Maria Chi | 歴史 |
この関数は3つのテーブルをうまく結合して、どの学生がどのコースに登録してるかを見せてくれる。
RAISE NOTICEとRETURN QUERYの組み合わせ
時々、RETURN QUERYとRAISE NOTICEを同じ関数で使って、実行状況や途中経過を見たいこともあるよ。
例えば、学生データを返しつつ、進行状況をメッセージで表示する関数:
CREATE OR REPLACE FUNCTION debug_students()
RETURNS TABLE(student_id INT, student_name TEXT) AS $$
DECLARE
count_students INT;
BEGIN
-- 学生数をカウント
SELECT COUNT(*) INTO count_students FROM students;
RAISE NOTICE '学生の合計: %', count_students;
-- 学生データを返す
RETURN QUERY
SELECT id, name FROM students;
RAISE NOTICE '関数の実行が完了したよ。';
END;
$$ LANGUAGE plpgsql;
もしstudentsテーブルがまだなければ、作ってデータを入れてね:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
INSERT INTO students (name) VALUES
('Otto Song'),
('Alex Lin'),
('Anna Vel'),
('Maria Chi');
この関数を呼ぶと:
SELECT * FROM debug_students();
データとメッセージの両方が出る:
| student_id | student_name |
|---|---|
| 1 | Otto Song |
| 2 | Alex Lin |
| 3 | Anna Vel |
| 4 | Maria Chi |
コンソールのメッセージ出力:
NOTICE: 学生の合計: 4
NOTICE: 関数の実行が完了したよ。
よくあるミス
RAISE NOTICEでの変数ミス: 変数の宣言を忘れたり、名前を間違えたりすると、variable does not existエラーになる。変数がちゃんと宣言されてるか確認しよう。
戻り値の型ミス: RETURN QUERYを使う時、関数作成時にRETURNS TABLEを指定しないとPostgreSQLがエラーを出す。返すデータと型が合ってるかチェックしよう。
RAISEのプレースホルダー数ミス: %の数と変数の数が合わないとエラーになる。例えば:
RAISE NOTICE '値: %, %', value1;
これは2つ目の変数がないのでエラーになるよ。
GO TO FULL VERSION