CodeGym /コース /SQL SELF /SQLクエリから関数を呼び出す方法

SQLクエリから関数を呼び出す方法

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

例えば、複雑な計算やデータ処理用の関数を持っているとするよ。もしSQLクエリに関数を組み込めなかったら、こんな感じで作業することになる:

  1. PythonやJavaScriptみたいなプログラミング言語から関数を呼び出す。
  2. その結果をSQLクエリに渡す。

これ、正直めんどくさいよね!PostgreSQLなら関数をSQLクエリに直接組み込めるから、コード量も減るし、処理も速くなるし、サーバーへのリクエストも減らせる。特にこんな時に便利:

  • 計算の自動化。
  • データ挿入前のバリデーション。
  • 既存データの修正。

SELECTで関数を呼ぶ

まずは基本から。普通のSELECTクエリで関数を使う方法を見てみよう。例えばstudentsテーブルがあって、学生の誕生日から今の年齢を返す関数を書きたいとする。

ステップ1:関数を書く

calculate_ageという関数を作って、誕生日を受け取って年齢を返すようにしよう:

CREATE OR REPLACE FUNCTION calculate_age(birth_date DATE) RETURNS INT AS $$
BEGIN
    RETURN DATE_PART('year', AGE(NOW(), birth_date))::INT;
END;
$$ LANGUAGE plpgsql;

ステップ2:SELECTクエリで関数を使う

これで、テーブルの各レコードに対して関数を呼び出せる:

SELECT id, name, calculate_age(birth_date) AS age FROM students;

何が起きてる?

  • studentsテーブルの各行ごとにcalculate_age関数が年齢を計算する。
  • 返された値はageカラムに表示される。

結果例:

id name age
1 オットー 21
2 アンナ 25
3 アレックス 22

ね、全然難しくないし、結果もきれいでプロっぽいでしょ。

INSERTで関数を呼ぶ

データ挿入時にも関数は超便利。例えばlogsテーブルがあって、ユーザーのアクションを記録したいとする。関数で自動的にメッセージを作って挿入したいよね。

ステップ1:関数を作る

generate_log_messageという関数を書いて、ユーザー名とアクションを受け取ってメッセージを返すようにしよう:

CREATE OR REPLACE FUNCTION generate_log_message(username TEXT, action TEXT) RETURNS TEXT AS $$
BEGIN
    RETURN username || ' performed action: ' || action || ' at ' || NOW();
END;
$$ LANGUAGE plpgsql;

ステップ2:INSERTで関数を使う

行を追加する時に関数を呼び出してメッセージを挿入しよう:

INSERT INTO logs (message)
VALUES (generate_log_message('オットー', 'サイトにログイン'));

結果:

id message
1 オットー performed action: サイトにログイン at 2023-10-26 12:00:00

関数が全部やってくれる:テキストのフォーマットもタイムスタンプも自動。こういうの、ルーチン作業の自動化に最高だよね。

UPDATEで関数を呼ぶ

テーブルのデータを修正する時にも関数は使える。例えばstudentsテーブルで、グループ名を新しいコース用に変換したいとする。

ステップ1:関数を作る

promote_studentという関数を書いて、古いグループ(例:101)を受け取って新しいグループ(例:201)を返すようにしよう:

CREATE OR REPLACE FUNCTION promote_student(old_group TEXT) RETURNS TEXT AS $$
BEGIN
    RETURN '2' || RIGHT(old_group, LENGTH(old_group) - 1);
END;
$$ LANGUAGE plpgsql;

ステップ2:UPDATEで関数を使う

全員のグループを更新しよう:

UPDATE students
SET group_name = promote_student(group_name);

結果:

id name group_name
1 オットー 201
2 アンナ 202
3 アレックス 203

関数を呼ぶだけでグループ名が一気に変わるの、ちょっと魔法みたいでしょ。

WHERE条件で関数を使う

フィルタリング条件でも関数は使える。さっきの学生の年齢の例をもう少し広げてみよう。

ステップ1:年齢でフィルタ

作ったcalculate_age関数を使って、20歳より上の学生だけ選ぼう:

SELECT id, name, birth_date
FROM students
WHERE calculate_age(birth_date) > 20;

結果:

id name birth_date
2 アンナ 1998-05-15
3 アレックス 1999-11-09

ここでは、各学生の年齢を関数でその場で計算してるんだ。

集約関数との組み合わせ

ちょっと難易度アップ。22歳未満の学生の合計人数を数えたいとする。関数はCOUNT()みたいな集約関数ともバッチリ組み合わせられるよ。

SELECT COUNT(*)
FROM students
WHERE calculate_age(birth_date) < 22;

何が起きてる?

  • calculate_age関数がフィルタ条件で使われてる。
  • COUNT(*)が条件に合う行数を数えてる。

実際の使い方例

データバリデーションの自動化。 例えば、全学生の年齢が普通の範囲(例:18~30歳)に入ってるかチェックしたいとする。チェック用の関数を書いてWHERE条件で使おう。

SELECT id, name
FROM students
WHERE NOT (calculate_age(birth_date) BETWEEN 18 AND 30);

データ挿入の最適化。 ネットショップで働いてるとしよう。注文の合計金額をクライアント側で計算する代わりに、テーブルordersにデータ追加時に関数で計算しちゃおう。

INSERT INTO orders (user_id, total_price)
VALUES (1, calculate_total_price(ARRAY[5, 10, 15]));

関数呼び出し時のよくあるミス

関数をガンガン使い始めると、たまにエラーに出くわすことも。よくあるパターンと対策を紹介するね:

権限が足りない。 関数やテーブルのオーナーじゃない場合、PostgreSQLが実行を拒否することがある。関数実行権限があるか確認しよう。

型が合わない。 関数に渡す引数の型に注意。例えば、関数がDATEを期待してるのに文字列を渡すとエラーになる。明示的に型変換しよう:

SELECT calculate_age('2000-01-01'::DATE);

関数内の構文ミス。 関数がエラーを返すと、クエリ全体が失敗することもある。使う前にしっかりテストしよう。

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