想像一下,你有個用來做複雜計算或資料處理的函式。如果不能把函式整合進 SQL 查詢,你大概會這樣搞:
- 從某個程式語言(像是 Python 或 JavaScript)呼叫函式。
- 把結果傳給 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 表格,記錄使用者的動作。我們想用函式自動產生訊息內容來插入 log。
步驟 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 裡用函式
現在插入 log 時直接呼叫函式:
INSERT INTO logs (message)
VALUES (generate_log_message('奧托', '登入網站'));
結果:
| id | message |
|---|---|
| 1 | 奧托 performed action: 登入網站 at 2023-10-26 12:00:00 |
函式幫我們搞定格式化和加上時間戳,超方便!這就是函式自動化日常操作的好例子。
在 UPDATE 裡呼叫函式
函式也可以用來修改表格資料。假設我們有 students 表格,想用函式把學生的 group 名稱升級到新學年。
步驟 1:寫函式
寫個 promote_student 函式,傳入舊 group(像 101),回傳新 group(像 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 裡用函式
把所有學生的 group 都更新:
UPDATE students
SET group_name = promote_student(group_name);
結果:
| id | name | group_name |
|---|---|---|
| 1 | 奧托 | 201 |
| 2 | 安娜 | 202 |
| 3 | 阿列克斯 | 203 |
你看,呼叫函式就像魔法一樣,舊 group 直接變成新 group!
在 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);
函式內部語法錯誤。 如果函式回傳錯誤,整個查詢都會失敗。記得先好好測試你的函式!
GO TO FULL VERSION