CodeGym /コース /SQL SELF /関数とプロシージャの違い

関数とプロシージャの違い

SQL SELF
レベル 51 , レッスン 4
使用可能

多くのプログラミング言語では、関数とプロシージャの違いはほとんどない。でもSQLでは違うんだ。PostgreSQLの関数とプロシージャは、単なるコードを実行する2つの方法じゃなくて、考え方自体が違うんだよ。

SQLの関数は、データベースのデータを変更できない。渡されたデータだけを使って結果を返すためのもの。主にSELECTクエリの中で使うために作られてる。

SQLのプロシージャは、データベースを変更するために作られてる。だからトランザクションを扱える(関数とは違って)、データベースに書き込みもできる。でもSELECTクエリの中では使えない。

ざっくり比較するとこんな感じ:

特徴 関数 (FUNCTION) プロシージャ (PROCEDURE)
データを返す ✅ はい (RETURNS ...) ❌ いいえ(アクションだけ実行)
呼び出し方法 SELECT, PERFORM CALL
クエリ内で使える ✅ はい ❌ いいえ
DOで使える ✅ はい ❌ いいえ
COMMIT, ROLLBACK対応 ❌ いいえ ✅ はい
PostgreSQLに登場した時期 最初から バージョン11から

SQLでの違い

普通のSQLだと、関数は式みたいなもの:計算して値を返すんだ。 プロシージャは命令何かをするけど、式の中では使えない。

SQLの関数

SELECT calculate_discount(200);
  • WHEREORDER BYINSERTUPDATEなどで使える
  • ピュアじゃないとダメ:データベースの状態を変えちゃダメ(IMMUTABLE/STABLEの場合)

SQLのプロシージャ

CALL process_order(123);
  • 結果を返さない
  • COMMITROLLBACKRAISE、ループも使える

PL/pgSQLでの違い

PostgreSQLの関数は、計算のグループみたいなもの。 めっちゃ柔軟で、パラメータ渡したり、if文やループ、カーソル、サブクエリ、行やスカラー、テーブルも返せる。

PL/pgSQLの関数

CREATE FUNCTION square(x INT) RETURNS INT AS $$
BEGIN
    RETURN x * x;
END;
$$ LANGUAGE plpgsql;

ポイント:

  • RETURNSが必須
  • DECLAREBEGINENDLOOPIFCASEが使える
  • COMMIT/ROLLBACKは使えない
  • SELECTUPDATECHECKWHERERETURNINGで呼び出せる

呼び出し例:

SELECT square(5);  -- 25を返す

PL/pgSQLのプロシージャ

プロシージャはアクションを管理する仕組み。 こんな時にピッタリ:

  • たくさんのステップをロジック付きで実行したいとき
  • 大量のデータを更新・挿入したいとき
  • トランザクション管理したいとき:COMMITROLLBACKSAVEPOINT
CREATE PROCEDURE log_event(msg TEXT) AS $$
BEGIN
    INSERT INTO logs(message) VALUES (msg);
    COMMIT;
END;
$$ LANGUAGE plpgsql;

ポイント:

  • RETURNSなし
  • CALLでしか呼べない
  • COMMITROLLBACKSAVEPOINTが使える
  • バッチ処理、マイグレーション、ETLに最適

呼び出し例:

CALL log_event('処理完了');

なぜ関数とプロシージャは分かれてるの?

だってSQLでの目的が違うから:

関数 プロシージャ
「何かを計算して返す」 「何かを実行して結果は返さない」
SQLから呼び出し コマンドとして呼び出し
トランザクション管理できない トランザクション管理できる
SELECTJOINWHEREで使う CALLやスクリプトで使う

プロシージャの最大のメリット — COMMIT

プロシージャは自分の中でトランザクションを管理できる。 つまり、プロシージャの中で直接:

BEGIN;
-- ロジック
SAVEPOINT point1;
-- 更新試行
ROLLBACK TO point1;
COMMIT;

ってできる。関数ではCOMMITROLLBACKは禁止。 やろうとすると:ERROR: invalid transaction termination in functionって怒られる。

つまり、関数は決定的で安全じゃなきゃダメ、プロシージャは「汚れ仕事」もOK — クリーンアップ、ログ、挿入とか。

比較表

特徴 FUNCTION PROCEDURE
値を返す RETURNS
SELECTで使える
呼び出し SELECTPERFORMDO CALLのみ
トリガーで使える ❌(関数のみ)
内部トランザクション(COMMIT ❌ 禁止 ✅ OK
OUTパラメータの使い方 RETURNS TABLERECORD OUTパラメータを直接
計算向き 🚫 向いてない
ETLやロード向き 🚫 限定的 ✅ 最適
カーソル使える ✅ はい ✅ はい

どっちを使う?

関数を使う場合:

  • 値を返したいとき
  • SELECTで呼び出したり、データをフィルタしたいとき
  • 簡単な計算、チェック、SQLのラッパーとして

プロシージャを使う場合:

  • 複雑な処理をしたいとき
  • トランザクション管理が必要なとき
  • バッチ処理、データ移行、アーカイブ、ログなど
1
アンケート/クイズ
制御構造、レベル 51、レッスン 4
使用不可
制御構造
制御構造
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION