想像一下,我們有一個存放學生資料的資料表。這個表裡面我們需要每次新增學生時自動更新 last_modified(紀錄最後一次修改的時間)。這個欄位很重要,因為可以追蹤資料變動跟管理資料。
流程大概是這樣:
- 每當有新資料加進表格,
last_modified欄位會自動設成現在的日期和時間。 - 我們會用
AFTER INSERT這個觸發器,讓它在資料插入成功後自動執行。
寫一個給觸發器用的 function
首先要先寫一個 PL/pgSQL 的 function。這個 function 會幫我們更新 last_modified 欄位。function 是觸發器一定要有的,因為觸發器本身只是指示要做什麼,實際邏輯都在 function 裡面。
我們先來建立資料表:
-- 建立 students 資料表
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
age INT NOT NULL,
last_modified TIMESTAMP
);
接下來寫一個 function 來更新 last_modified:
-- 更新 last_modified 的 function
CREATE OR REPLACE FUNCTION update_last_modified()
RETURNS TRIGGER AS $$
BEGIN
-- 把現在時間設到 last_modified 欄位
NEW.last_modified := NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
來看看這個 function 到底在幹嘛:
CREATE OR REPLACE FUNCTION update_last_modified()— 建立一個叫update_last_modified的 function。如果已經有同名的會直接覆蓋。RETURNS TRIGGER— 這個 function 是給觸發器用的。NEW.last_modified := NOW();— 用NOW()function 把現在的日期時間寫進last_modified。RETURN NEW;— 回傳更新後的資料。這是AFTER觸發器一定要做的。
建立觸發器
寫好 function 之後,我們就可以把觸發器綁到 students 這個表。做法如下:
-- 新增資料後自動執行的觸發器
CREATE TRIGGER set_last_modified
AFTER INSERT ON students
FOR EACH ROW
EXECUTE FUNCTION update_last_modified();
這裡做了什麼:
CREATE TRIGGER set_last_modified— 建立一個叫set_last_modified的觸發器。AFTER INSERT— 這個觸發器會在資料插入成功後執行。ON students— 綁定在students這個表。FOR EACH ROW— 每加一筆資料就執行一次。EXECUTE FUNCTION update_last_modified();— 執行我們剛剛寫的 function。
小提醒:觸發器(set_last_modified)跟 function(update_last_modified)的名字你可以自己取,不過建議還是照慣例命名,這樣以後看程式碼比較不會亂。
測試觸發器
來測試一下我們的觸發器。先加幾筆資料到 students 表:
-- 插入資料到表格
INSERT INTO students (name, age) VALUES ('伊凡 伊凡諾夫', 20);
INSERT INTO students (name, age) VALUES ('安娜 彼得羅娃', 22);
現在來看看表格裡的資料:
-- 查詢表格資料
SELECT * FROM students;
預期結果大概會長這樣:
| id | name | age | last_modified |
|---|---|---|---|
| 1 | 奧托 明 | 20 | 2023-10-10 14:30:45 |
| 2 | 安娜 松 | 22 | 2023-10-10 14:31:12 |
你會發現 last_modified 欄位已經自動填上每筆資料新增時的日期和時間了。
可能遇到的錯誤
- 錯誤:"relation does not exist" 建立觸發器時出現。這通常是因為
students表還沒建立。記得先建立表格再建觸發器。 - 權限錯誤。如果你的資料庫使用者沒有建立 function 或觸發器的權限,觸發器就建不起來。檢查一下權限設定。
- 觸發器沒呼叫 function。如果你忘了寫
EXECUTE FUNCTION update_last_modified(),觸發器就不會做事。
進階:加條件的觸發器
實務上有時候會想讓觸發器只在特定情況下執行。比如說,如果 age 小於 18,我們就不想更新 last_modified。這時可以用 WHEN 條件:
-- 有條件的觸發器
CREATE TRIGGER set_last_modified
AFTER INSERT ON students
FOR EACH ROW
WHEN (NEW.age >= 18)
EXECUTE FUNCTION update_last_modified();
這樣 last_modified 只會在學生年齡 >= 18 的時候才會被更新。
實際應用
像這種觸發器在專案裡超常見。舉幾個例子:
- 自動更新資料最後修改時間(就像我們現在做的)。
- 追蹤資料異動,把變動紀錄寫進 log 表。
- 確保資料正確性,比如在執行操作前檢查關聯表。
- 做資料稽核,符合法規或公司規定。
這些技巧對你以後做銀行系統、庫存管理、CRM 這種很重視資料正確性的系統都超有幫助。
GO TO FULL VERSION