CodeGym /コース /SQL SELF /RAISE NOTICE、RETURN QUERYのオペレーター

RAISE NOTICE、RETURN QUERYのオペレーター

SQL SELF
レベル 50 , レッスン 3
使用可能

RAISE NOTICERETURN 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 — エラーを発生させる(これは後でやる)。

デバッグにはNOTICEDEBUGがオススメ。実行を止めずに使えるから便利だよ。

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 NOTICERETURN QUERYの組み合わせ

時々、RETURN QUERYRAISE 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つ目の変数がないのでエラーになるよ。

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