CodeGym /コース /SQL SELF /関数の実行管理: PERFORM

関数の実行管理: PERFORM

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

PERFORMってPostgreSQLの世界だと、無口なヒーローみたいな存在なんだ。やるべきことをサッとやって、返り値とか何も残さずに消えていく感じ。このコマンドは、PL/pgSQLの関数の中でSQLクエリを実行したいけど、結果を処理したり保存したりする必要がないときに使うよ。PERFORMの主な役割は、何かを起こすためにクエリを呼び出すこと。例えばデータの変更や、別の関数の呼び出しとかで、結果を受け取ることじゃないんだ。

PERFORMは、クエリの結果がいらないときに使うんだ。普通のSELECTは、何かしら結果を使う前提だけど、PERFORMはただクエリを実行して、何も言わずに次に進む。特に、関数を副作用(例えばログに書き込むとか)のためだけに呼び出すときに便利。こういう使い方だと、コードがシンプルで分かりやすくなるよ。余計なことが減って、意味がはっきりする。

PERFORMの使い方例

関数の呼び出し

実際の例で見てみよう。例えば、log_actionっていう関数があって、ユーザーのアクションをログに記録するものだとする。この関数は何も返さないし、ただ動いてくれればOK。PERFORMを使うとこうなるよ:

CREATE OR REPLACE FUNCTION log_action(user_id INT, action TEXT) RETURNS VOID AS $$
BEGIN
    INSERT INTO logs (user_id, action, log_time)
    VALUES (user_id, action, NOW());
END;
$$ LANGUAGE plpgsql;

-- そしてPERFORMでこの関数を呼び出す:
PERFORM log_action(5, 'ユーザーがログインした');

ここで何が起きてるかというと、PERFORMがlog_action関数を呼び出して、logsテーブルにレコードを追加してるんだ。ポイントは、関数の返り値は無視されるってこと。副作用のためだけに使ってるんだよ。

データの更新

たまにPERFORMは、クエリの結果に興味がないけどデータを変更したいときにも便利。例えば、ordersテーブルの注文ステータスを更新する場合:

CREATE OR REPLACE FUNCTION update_order_status(order_id INT, new_status TEXT) RETURNS VOID AS $$
BEGIN
    UPDATE orders
    SET status = new_status
    WHERE id = order_id;
END;
$$ LANGUAGE plpgsql;

-- この関数をPERFORMで呼び出す:
PERFORM update_order_status(101, '発送済み');

ここではupdate_order_statusが注文ID101のステータスを更新してる。関数内のSQLクエリの結果は気にしないから、PERFORMがぴったりなんだ。

補助的な操作の実行

関数の中には、複雑な処理をサポートするための「補助的」なロジックが入ってることもあるよね。例えば、テーブルを更新した後にキャッシュをクリアしたい場合:

CREATE OR REPLACE FUNCTION clear_cache() RETURNS VOID AS $$
BEGIN
    DELETE FROM cache_table;
END;
$$ LANGUAGE plpgsql;

-- 別の関数の中で呼び出す:
CREATE OR REPLACE FUNCTION update_product(product_id INT, new_price NUMERIC) RETURNS VOID AS $$
BEGIN
    UPDATE products
    SET price = new_price
    WHERE id = product_id;

    -- データ変更後にキャッシュをクリア:
    PERFORM clear_cache();
END;
$$ LANGUAGE plpgsql;

これが魔法みたいなところで、PERFORMを使えば、結果がいらない関数をどんどん呼び出して処理を進められるんだ。

実践課題

PERFORMが開発者の生活をどれだけ楽にしてくれるか、いくつか例を見てみよう。

例1: 手順の各ステージのログ記録

例えば、複雑な支払い処理の手順があって、その各ステージをログに記録したいとする。情報を書き込むlog_stage関数を作って、PERFORMで使う:

CREATE OR REPLACE FUNCTION log_stage(stage_name TEXT) RETURNS VOID AS $$
BEGIN
    INSERT INTO process_logs(stage, log_time)
    VALUES (stage_name, NOW());
END;
$$ LANGUAGE plpgsql;

-- こんな感じの手順:
CREATE OR REPLACE FUNCTION process_payment(payment_id INT) RETURNS VOID AS $$
BEGIN
    -- 開始をログ
    PERFORM log_stage('支払い処理開始');

    -- 最初のステージ
    UPDATE payments
    SET status = '処理中'
    WHERE id = payment_id;

    PERFORM log_stage('支払いステータス更新');

    -- 最終ステージ
    UPDATE payments
    SET status = '完了'
    WHERE id = payment_id;

    PERFORM log_stage('支払い完了');
END;
$$ LANGUAGE plpgsql;

ここではlog_stageをPERFORMで呼び出して、各ステージごとに実行状態を記録してる。これでデバッグもしやすくなるよ。

例2: 通知のアクティベート

通知システムがあって、重要なアクションごとに通知を送りたいとする。PERFORMで通知用関数を呼び出せる:

CREATE OR REPLACE FUNCTION send_notification(user_id INT, message TEXT) RETURNS VOID AS $$
BEGIN
    INSERT INTO notifications (user_id, message, created_at)
    VALUES (user_id, message, NOW());
END;
$$ LANGUAGE plpgsql;

-- 手順の中で使う:
CREATE OR REPLACE FUNCTION complete_task(task_id INT) RETURNS VOID AS $$
DECLARE
    user_id INT;
BEGIN
    -- タスクの担当者を取得
    SELECT assigned_to INTO user_id
    FROM tasks
    WHERE id = task_id;

    -- タスクを完了
    UPDATE tasks
    SET status = '完了'
    WHERE id = task_id;

    -- 通知を送信
    PERFORM send_notification(user_id, 'あなたのタスクが完了しました');
END;
$$ LANGUAGE plpgsql;

ここでもPERFORMは副作用(通知送信)だけに集中して、関数の返り値は無視してる。

便利なヒントとよくあるミス

PERFORMを使うときは、いくつか注意点があるよ。例えば、PERFORMはクエリがデータを返したかどうかをチェックしない。つまり、関数やSQLクエリの結果がロジック的に重要な場合は、SELECT INTOを使った方がいい。例を見てみよう:

-- 潜在的なミス
PERFORM some_function_that_must_return_value();

-- 修正例
SELECT some_function_that_must_return_value() INTO some_variable;

もう一つよくあるミスは、PERFORMを使うべきじゃない場面、つまりクエリの結果が必要なときに使っちゃうこと。そういうときは、ちゃんと結果を受け取ってチェックしよう。

実際のプロジェクトでは、PERFORMを使うことで関数や手順がシンプルで読みやすく、デバッグもしやすくなる。ログ記録(RAISE NOTICE)や、PostgreSQLの組み込み診断関数(current_query()など)と組み合わせると、信頼性が高くて管理しやすいシステム作りに役立つよ。

2
タスク
SQL SELF, レベル 55, レッスン 3
ロック未解除
PERFORMを使ったロギング関数の呼び出し
PERFORMを使ったロギング関数の呼び出し
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION