| この記事の要点 |
|
ストアド・ファンクションとは
必ず戻り値を 1 つ返す、データベース内に保存される名前付きルーチン (関数) です。SQL の中で組み込み関数 (UPPER や SUBSTR など) と同じように呼び出せます。
-- Oracle / PL/SQL
CREATE OR REPLACE FUNCTION calc_tax(p_amount IN NUMBER)
RETURN NUMBER
DETERMINISTIC
AS
BEGIN
RETURN ROUND(p_amount * 0.10);
END;
/
-- 使い方 — SELECT 中で普通の関数として呼べる
SELECT order_id, amount, calc_tax(amount) AS tax
FROM orders;
プロシージャとの違い
| 項目 | ファンクション | プロシージャ |
|---|---|---|
| 戻り値 | 必ず 1 つ返す | 戻り値なし (OUT 引数で複数返す) |
| SELECT / WHERE 句での呼び出し | 可 | 不可 |
| 呼び出し構文 | SELECT my_func(...) | CALL my_proc(...) / EXEC my_proc |
| トランザクション制御 (COMMIT / ROLLBACK) | 原則不可 (Oracle はオプション) | 可 |
| 副作用 (INSERT / UPDATE) | 非推奨 / DB によっては禁止 | 推奨利用ケース |
| 典型用途 | 値の計算、変換、参照 | 業務処理、複数表更新 |
各 DB の方言
Oracle PL/SQL
CREATE OR REPLACE FUNCTION get_full_name(p_emp_id IN NUMBER)
RETURN VARCHAR2
IS
v_name VARCHAR2(100);
BEGIN
SELECT last_name || ' ' || first_name
INTO v_name
FROM employees
WHERE emp_id = p_emp_id;
RETURN v_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN NULL;
END;
/
-- 呼び出し
SELECT get_full_name(1234) FROM dual;
PostgreSQL (plpgsql)
CREATE OR REPLACE FUNCTION get_full_name(p_emp_id INTEGER)
RETURNS TEXT
LANGUAGE plpgsql
IMMUTABLE -- 同じ引数なら同じ結果
AS $$
DECLARE
v_name TEXT;
BEGIN
SELECT last_name || ' ' || first_name
INTO v_name
FROM employees WHERE emp_id = p_emp_id;
RETURN v_name;
END;
$$;
-- 呼び出し
SELECT get_full_name(1234);
PostgreSQL は plpgsql 以外に plpython3u / plperl / SQL 等を選択できます。簡単な集計なら LANGUAGE SQL の方が高速。
-- SQL 言語版 (インライン展開されやすく速い)
CREATE OR REPLACE FUNCTION add_tax(amount NUMERIC)
RETURNS NUMERIC
LANGUAGE SQL
IMMUTABLE
AS $$
SELECT ROUND(amount * 1.10, 0)
$$;
MySQL
DELIMITER //
CREATE FUNCTION get_full_name(p_emp_id INT)
RETURNS VARCHAR(100)
DETERMINISTIC -- 同じ引数なら同じ戻り値
READS SQL DATA -- DML せず SELECT する宣言
BEGIN
DECLARE v_name VARCHAR(100);
SELECT CONCAT(last_name, ' ', first_name) INTO v_name
FROM employees WHERE emp_id = p_emp_id;
RETURN v_name;
END //
DELIMITER ;
-- 呼び出し
SELECT get_full_name(1234);
MySQL の制限 — DETERMINISTIC / NO SQL / READS SQL DATA / MODIFIES SQL DATA / CONTAINS SQL のいずれかを必ず宣言する必要があります。バイナリログを有効化している場合、宣言が無いと作成エラー。
SELECT 内で呼び出す注意 — N+1 と関数索引
1 行ごとに重い処理を呼ぶと、件数に比例して劇的に遅くなります。
-- ❌ 100 万行 SELECT 内で関数呼び出し
SELECT order_id, calc_tax(amount) AS tax
FROM orders;
-- → 100 万回の関数呼出 + 100 万回のコンテキストスイッチ
-- ✅ Deterministic 宣言で結果キャッシュが効くケースがある
CREATE OR REPLACE FUNCTION calc_tax(p_amount NUMBER)
RETURN NUMBER DETERMINISTIC -- ← Oracle はクエリ実行中に結果キャッシュ
AS BEGIN
RETURN ROUND(p_amount * 0.10);
END;
/
-- ✅ 関数索引 (Function-Based Index) を張ってインデックスを効かせる
CREATE INDEX idx_orders_tax ON orders(calc_tax(amount));
-- ✅ 列に持たせて更新時に計算 (Generated Column)
ALTER TABLE orders
ADD tax_amount NUMBER GENERATED ALWAYS AS (ROUND(amount * 0.10));
CREATE INDEX idx_orders_tax ON orders(tax_amount);
表を返すファンクション (PIPELINED / Table-Valued)
1 つの値だけでなく、結果セット (表) を返すこともできます。FROM 句から呼べるので、ビューより柔軟。
-- PostgreSQL: SETOF / TABLE
CREATE OR REPLACE FUNCTION recent_orders(p_user_id INT)
RETURNS TABLE(order_id INT, amount NUMERIC, created_at TIMESTAMP)
LANGUAGE SQL
AS $$
SELECT order_id, amount, created_at
FROM orders
WHERE user_id = p_user_id
ORDER BY created_at DESC
LIMIT 100
$$;
-- FROM 句から呼べる
SELECT * FROM recent_orders(1234);
削除と一覧
-- 一覧
-- Oracle
SELECT object_name FROM user_objects WHERE object_type = 'FUNCTION';
-- PostgreSQL
\df
-- MySQL
SHOW FUNCTION STATUS WHERE Db = 'mydb';
-- 削除
DROP FUNCTION calc_tax;
FAQ
Q: ファンクションとビューの使い分け?
A: ビューは「保存された SELECT」で引数を取れません。引数で結果を変えたい場合はファンクション (Table-Valued) を選びます。
Q: 副作用 (INSERT/UPDATE) を起こすファンクションを書ける?
A: 技術的には可ですが 推奨されません。SELECT 中に呼ばれると意図しない件数更新が走り、再現困難なバグになります。副作用が必要なら Procedure に分けましょう。
Q: DETERMINISTIC を付けるとどう変わる?
A: 「同じ入力なら同じ結果」と宣言したことで、オプティマイザがキャッシュや関数索引を使えるようになります。実態が条件次第で結果が変わる場合に宣言すると、結果不整合のバグになるので注意。
子ページはありません
- 表(テーブル)
- 索引(インデックス)
- ビュー
- 制約
- 順序(シーケンス)
- シノニム
- トリガー
- パッケージ
- ストアド・ファンクション
- ストアド・プロシージャ
- ユーザー(USER)
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- MariaDB Monitor (mysql コマンド) の使い方 2026-10-14 15:21:02
- MariaDB の管理ツール (phpMyAdmin / DBeaver 等) 2026-10-14 15:21:02
- Google Custom Search JSON API|新規受付終了・移行期限と既存実装の確認 2026-10-14 14:50:13
- MySQL rootの初期パスワード確認|導入方式・Docker既存DB・復旧の注意 2026-10-14 14:39:34
- MySQL root パスワードの変更方法(ALTER USER / mysqladmin / パスワード忘れ時の復旧) 2026-10-14 14:39:34
- MySQL ALTER USER の使い方|パスワード変更・アカウントロック 2026-10-14 14:39:34
- MySQL ERROR 1129|ホスト遮断の原因・カウンタ・解除前の確認 2026-10-14 14:04:49
- MySQL ERROR 1820・1862|期限切れパスワードの安全な更新と確認 2026-10-14 14:04:49
- MySQL ERROR 1698|ソケット認証・OSユーザー・接続経路の確認 2026-10-14 14:04:49
- mysql_configが見つからない|mysqlclientの旧ビルドとpkg-configの確認 2026-10-14 13:36:32
- MySQLエラー一覧|番号・SQLSTATE別の原因と安全な確認手順 2026-10-14 13:36:32
- インストール直後にNetbeansが反応しない 2026-10-14 13:07:02
- NetBeans でよくあるエラー一覧と対処法 — JDK / Tomcat / PHP / メモリ不足 2026-10-14 13:07:02
- Apache NetBeans入門|起動JDK・プロジェクト作成・関連手順 2026-10-14 13:07:02
- 【Laravel】ページング(ページネーション)をする方法 2026-10-14 12:31:44