☕ NEW! 完成新手任務即可參加抽獎!LINE 星巴克禮券等你拿,名額有限!        🎉 推廣活動:邀請好友註冊 DevLearn,累積推薦抽 LINE 星巴克禮券! 活動詳情 →        🔥 活動期間 2026/4/1 - 5/31 |已有 0 人參加       
sql 中級

Trigger 觸發器

什麼是 Trigger?

比喻:Trigger 就像自動感應門 🚪

有人走近(事件發生)→ 門自動打開(觸發動作)。 當資料被新增/修改/刪除時,Trigger 會自動執行你預設的程式。


建立 Trigger(PostgreSQL)

-- Step 1:建立 Trigger 函數
CREATE OR REPLACE FUNCTION update_timestamp()
RETURNS TRIGGER                          -- ← 回傳類型必須是 TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
    NEW.UpdatedAt = CURRENT_TIMESTAMP;   -- ← NEW 代表即將寫入的新資料
    RETURN NEW;                          -- ← 回傳修改後的資料
END;
$$;

-- Step 2:建立 Trigger,綁定到表
CREATE TRIGGER trg_students_updated       -- ← Trigger 名稱
    BEFORE UPDATE                         -- ← 在 UPDATE 之前觸發
    ON Students                           -- ← 綁定到 Students 表
    FOR EACH ROW                          -- ← 每一列都觸發
    EXECUTE FUNCTION update_timestamp();  -- ← 執行的函數

逐行解析:

BEFORE UPDATE              -- 時機:在 UPDATE 實際執行之前
ON Students                -- 觸發表:Students
FOR EACH ROW               -- 範圍:影響到的每一列都觸發一次
EXECUTE FUNCTION update_timestamp()  -- 執行的動作

Trigger 的時機

時機 說明
BEFORE INSERT 新增前(可修改 NEW 的值)
AFTER INSERT 新增後(適合寫日誌)
BEFORE UPDATE 修改前(可修改 NEW 的值)
AFTER UPDATE 修改後(適合同步、通知)
BEFORE DELETE 刪除前(可取消刪除)
AFTER DELETE 刪除後(適合清理關聯資料)

NEW 和 OLD

CREATE OR REPLACE FUNCTION log_score_change()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
    -- NEW = 更新後的新值
    -- OLD = 更新前的舊值
    INSERT INTO ScoreLog (StudentId, OldScore, NewScore, ChangedAt)
    VALUES (
        OLD.Id,                          -- ← 學生 Id(新舊都一樣)
        OLD.Score,                       -- ← 舊分數
        NEW.Score,                       -- ← 新分數
        CURRENT_TIMESTAMP
    );
    RETURN NEW;
END;
$$;

CREATE TRIGGER trg_score_change
    AFTER UPDATE OF Score                -- ← 只在 Score 欄位被改時觸發
    ON Students
    FOR EACH ROW
    WHEN (OLD.Score IS DISTINCT FROM NEW.Score)  -- ← 值真的有變才觸發
    EXECUTE FUNCTION log_score_change();

實用範例:軟刪除

-- 不真的刪除,而是標記為已刪除
CREATE OR REPLACE FUNCTION soft_delete()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
    -- 攔截 DELETE,改成 UPDATE
    UPDATE Students
    SET IsDeleted = true, DeletedAt = CURRENT_TIMESTAMP
    WHERE Id = OLD.Id;

    RETURN NULL;                         -- ← 回傳 NULL = 取消原本的 DELETE
END;
$$;

CREATE TRIGGER trg_soft_delete
    BEFORE DELETE ON Students
    FOR EACH ROW
    EXECUTE FUNCTION soft_delete();

管理 Trigger

-- 暫時停用 Trigger
ALTER TABLE Students DISABLE TRIGGER trg_students_updated;

-- 重新啟用
ALTER TABLE Students ENABLE TRIGGER trg_students_updated;

-- 刪除 Trigger
DROP TRIGGER trg_students_updated ON Students;

-- 查看表的所有 Trigger
SELECT trigger_name, event_manipulation, action_timing
FROM information_schema.triggers
WHERE event_object_table = 'students';

⚠️ Trigger 注意事項

  1. 效能影響:每次操作都會觸發,大量寫入時會變慢
  2. 難除錯:隱式執行,出問題不容易發現
  3. 避免無限迴圈:Trigger A 更新表 → 觸發 Trigger B → 又更新 → 觸發 Trigger A...
  4. 現代替代方案:在應用程式層處理(EF Core Interceptor、Middleware 等)

💡 大家的想法 · 0

載入中...
💬 即時聊天室 🟢 0 人在線
😀 😎 🤓 💻 🎮 🎸 🔥
➕ 新問題
📋 我的工單
💬 LINE 社群
🔒
需要註冊才能使用此功能
註冊帳號即可解鎖測驗、遊戲、簽到、筆記下載等所有功能,完全免費!
免費註冊