CodeGym /コース /SQL SELF /トリガーでタスクを自動化しよう

トリガーでタスクを自動化しよう

SQL SELF
レベル 58 , レッスン 0
使用可能

例えば、君が大きなデータベースの管理者だと想像してみて。突然誰かが大事な情報をテーブルから消しちゃって、みんなが「誰がやったの!?」ってパニックになる。こういう事態を防ぐために、データベースには変更履歴を記録して、何が起きたか追跡できる仕組みがあるんだ。それがログ記録と監査(audit)だよ。

  • 変更ログは「何が、どう、いつ変わったか」の履歴を残すためのもの。
  • データ監査はもっと深くて、変更内容だけじゃなくて「誰がやったか」みたいな情報も記録するために使うよ。

「なぜ必要か」がわかったところで、今度は「どうやるか」を見ていこう!

ログ用テーブルを作ろう

トリガーを設定する前に、まずは変更ログを保存するテーブルが必要だよ。例えばこんな感じ:

-- 変更ログ用のテーブルを作成
CREATE TABLE change_logs (
    log_id SERIAL PRIMARY KEY,       -- ログレコードのユニークID
    table_name TEXT NOT NULL,        -- 変更があったテーブル名
    operation TEXT NOT NULL,         -- 操作タイプ: INSERT, UPDATE, DELETE
    change_time TIMESTAMP DEFAULT NOW(), -- 変更時刻
    old_data JSONB,                  -- 変更前データ(UPDATE/DELETE用)
    new_data JSONB                   -- 変更後データ(INSERT/UPDATE用)
);

これってどういう意味?

  1. log_id — 各ログレコードのユニークIDだよ。
  2. table_name — どのテーブルが変更されたか記録する。
  3. operation — 操作タイプ:INSERTUPDATEDELETE
  4. change_time — 変更があった正確な時刻を記録。
  5. old_datanew_data — 変更前と変更後のデータをJSON形式で保存する。

トリガーで変更をログに記録しよう

ログ用テーブルができたら、今度は例えばstudentsテーブルにトリガーを作ってみよう。これで新しい学生の追加、更新、削除の全部を記録できるよ。 やることはこんな感じ:

  1. PL/pgSQLでログ用テーブルにレコードを追加する関数を書く。
  2. studentsテーブルにトリガーを作る。

関数は操作タイプ(INSERTUPDATEDELETE)と、変更されたデータ(OLDNEW)を受け取るよ。

-- 変更をログテーブルに記録する関数
CREATE OR REPLACE FUNCTION log_student_changes()
RETURNS TRIGGER AS $$
BEGIN
    -- INSERT操作のログ
    IF TG_OP = 'INSERT' THEN
        INSERT INTO change_logs (table_name, operation, new_data)
        VALUES ('students', 'INSERT', row_to_json(NEW));

    -- DELETE操作のログ
    ELSIF TG_OP = 'DELETE' THEN
        INSERT INTO change_logs (table_name, operation, old_data)
        VALUES ('students', 'DELETE', row_to_json(OLD));

    -- UPDATE操作のログ
    ELSIF TG_OP = 'UPDATE' THEN
        INSERT INTO change_logs (table_name, operation, old_data, new_data)
        VALUES ('students', 'UPDATE', row_to_json(OLD), row_to_json(NEW));
    END IF;

    RETURN NULL; -- AFTERトリガーなのでNULLを返す
END;
$$ LANGUAGE plpgsql;

ここで:

  • TG_OP — 今の操作タイプ(INSERTUPDATEDELETE)が入ってる特別な変数。
  • row_to_json(OLD)row_to_json(NEW) — レコードをJSON形式に変換して保存しやすくする。
  • RETURN NULLAFTERトリガーだから、変更データは返さない。

じゃあ、この関数をstudentsテーブルに紐付けよう。

-- 変更ログ用のトリガーを作成
CREATE TRIGGER students_log_trigger
AFTER INSERT OR UPDATE OR DELETE ON students
FOR EACH ROW
EXECUTE FUNCTION log_student_changes();

これってどういうこと?

  • AFTER INSERT OR UPDATE OR DELETEstudentsテーブルで指定した操作が終わった後にトリガーが動く。
  • FOR EACH ROW — 変更された各行ごとにトリガーが実行される。
  • EXECUTE FUNCTION log_student_changes() — ログ記録用の関数を呼び出す。

トリガーをテストしよう

さあ、トリガーがちゃんと動くか試してみよう。

  1. 新しいレコードの挿入
INSERT INTO students (name, age, grade)
VALUES ('オットー・リン', 20, 'A');

ログテーブルに何が記録されたか見てみよう:

SELECT * FROM change_logs;

結果例:

log_id table_name operation change_time old_data new_data
1 students INSERT 2023-10-10 12:00:00 NULL {"name": "オットー・リン", "age": 20, ...}
  1. レコードの更新
UPDATE students
SET grade = 'B'
WHERE name = 'オットー・リン';

またログテーブルをチェック:

SELECT * FROM change_logs ORDER BY change_time DESC;

結果:

log_id table_name operation change_time old_data new_data
2 students UPDATE 2023-10-10 12:05:00 {"name": "オットー・リン", "age": ...} {"name": "オットー・リン", "age": ..., ...}
  1. レコードの削除
DELETE FROM students
WHERE name = 'オットー・リン';

またまたログを確認:

log_id table_name operation change_time old_data new_data
3 students DELETE 2023-10-10 12:10:00 {"name": "オットー・リン", "age": ...} NULL

実際の使い方の例

  1. 重要なテーブルの操作ログ:例えば銀行口座のテーブルは、全部の変更を記録して不正を防ぐ必要があるよ。
  2. システム監査:法令順守やユーザー行動の分析のために記録を残すこともできる。
  3. データ復元のための保険:誰かがうっかりデータを消しても、ログテーブルから復元できる。

注意点と落とし穴

トリガーでログ記録を実装するときは、パフォーマンスに注意しよう。トリガーが頻繁に発動すると、データベースに負荷がかかることもある。だから:

  • 本当に重要なテーブルだけログ記録を使おう。
  • ログが増えすぎたら、アーカイブ戦略を考えよう。

トリガーはギターの弦みたいなもの。ちゃんと調整すれば最高の音が出るし、面倒な作業を自動化してデータ管理もバッチリできるよ!

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