PERFORM 在 PostgreSQL 的世界裡就像個很酷的沉默英雄,來了、做完事就走,完全不會留下任何回傳資料的痕跡。這個指令就是給你在 PL/pgSQL 的函式裡執行 SQL 查詢時用的,如果你根本不想處理或儲存結果。PERFORM 的主要任務就是觸發查詢,讓某些事情發生,比如資料修改或呼叫另一個函式,而不是拿回傳值。
PERFORM 就是你不需要查詢結果時的好朋友。跟一般的 SELECT 不一樣,SELECT 會等你處理結果,但 PERFORM 只會執行查詢然後默默繼續往下走。這超適合你只是想讓函式做點事,不在乎它回什麼,比如寫 log。這樣寫起來程式碼更簡單、也更直觀:少了雜訊,多了重點。
PERFORM 的使用範例
呼叫函式
來看個實際例子。假設我們有個 log_action 函式,專門把使用者的動作寫進 log。這個函式不會回傳東西,我們只想讓它執行。用 PERFORM 就像這樣:
CREATE OR REPLACE FUNCTION log_action(user_id INT, action TEXT) RETURNS VOID AS $$
BEGIN
INSERT INTO logs (user_id, action, log_time)
VALUES (user_id, action, NOW());
END;
$$ LANGUAGE plpgsql;
-- 接下來用 PERFORM 來呼叫這個函式:
PERFORM log_action(5, '使用者已登入');
這裡發生什麼事?PERFORM 叫了 log_action,它會在 logs 表裡加一筆紀錄。記得:函式的回傳值會被忽略。我們只在乎它的副作用,不是回傳什麼。
更新資料
有時候 PERFORM 很適合用來執行資料變更查詢,但你根本不在意結果。例如,更新 orders 表裡訂單的狀態:
CREATE OR REPLACE FUNCTION update_order_status(order_id INT, new_status TEXT) RETURNS VOID AS $$
BEGIN
UPDATE orders
SET status = new_status
WHERE id = order_id;
END;
$$ LANGUAGE plpgsql;
-- 用 PERFORM 來呼叫這個函式:
PERFORM update_order_status(101, '已出貨');
這裡 update_order_status 會把 id 是 101 的訂單狀態改掉。我們不在乎 SQL 查詢的結果,所以 PERFORM 超適合。
執行輔助操作
有時候函式裡會有一些小小的「輔助」邏輯,幫忙完成複雜流程。比如說,更新完資料表後要清空 cache:
CREATE OR REPLACE FUNCTION clear_cache() RETURNS VOID AS $$
BEGIN
DELETE FROM cache_table;
END;
$$ LANGUAGE plpgsql;
-- 在另一個函式裡呼叫它:
CREATE OR REPLACE FUNCTION update_product(product_id INT, new_price NUMERIC) RETURNS VOID AS $$
BEGIN
UPDATE products
SET price = new_price
WHERE id = product_id;
-- 資料改完後清空 cache:
PERFORM clear_cache();
END;
$$ LANGUAGE plpgsql;
這就是魔法啦:你可以用 PERFORM 連續執行一堆動作,完全不用理會回傳值。
實戰小練習
來看幾個 PERFORM 怎麼讓開發者生活更輕鬆的例子。
範例 1:記錄程序每個階段
假設我們有個很複雜的付款處理程序,要追蹤每個階段並寫進 log。我們可以定義一個 log_stage 函式來寫資料,然後用 PERFORM:
CREATE OR REPLACE FUNCTION log_stage(stage_name TEXT) RETURNS VOID AS $$
BEGIN
INSERT INTO process_logs(stage, log_time)
VALUES (stage_name, NOW());
END;
$$ LANGUAGE plpgsql;
-- 這是程序範例:
CREATE OR REPLACE FUNCTION process_payment(payment_id INT) RETURNS VOID AS $$
BEGIN
-- 記錄開始
PERFORM log_stage('開始付款處理');
-- 執行第一階段
UPDATE payments
SET status = '處理中'
WHERE id = payment_id;
PERFORM log_stage('已更新付款狀態');
-- 執行最後階段
UPDATE payments
SET status = '已完成'
WHERE id = payment_id;
PERFORM log_stage('付款已完成');
END;
$$ LANGUAGE plpgsql;
這裡 log_stage 用 PERFORM 來記錄每個階段的狀態,讓我們的程式碼更好 debug。
範例 2:觸發通知
想像一下你有個通知系統,每次有重要動作都要發通知。PERFORM 可以用來呼叫負責這件事的函式:
CREATE OR REPLACE FUNCTION send_notification(user_id INT, message TEXT) RETURNS VOID AS $$
BEGIN
INSERT INTO notifications (user_id, message, created_at)
VALUES (user_id, message, NOW());
END;
$$ LANGUAGE plpgsql;
-- 在程序裡用:
CREATE OR REPLACE FUNCTION complete_task(task_id INT) RETURNS VOID AS $$
DECLARE
user_id INT;
BEGIN
-- 取得任務負責人
SELECT assigned_to INTO user_id
FROM tasks
WHERE id = task_id;
-- 完成任務
UPDATE tasks
SET status = '已完成'
WHERE id = task_id;
-- 發送通知
PERFORM send_notification(user_id, '你的任務已完成');
END;
$$ LANGUAGE plpgsql;
這裡 PERFORM 讓你只專注在副作用(發通知),不用理會函式回傳什麼。
實用小技巧與常見錯誤
用 PERFORM 時有幾個重點要注意。比如說,PERFORM 不會檢查查詢有沒有回傳資料。 這代表如果你真的需要查詢或函式的結果來決定流程,還是要用 SELECT INTO。來看個例子:
-- 潛在錯誤
PERFORM 必須回傳值的函式();
-- 正確寫法
SELECT 必須回傳值的函式() INTO some_variable;
另一個常見錯誤是你明明需要查詢結果(比如驗證資料),卻用 PERFORM。這種情況當然還是要拿回傳值來檢查。
在實際專案裡,PERFORM 讓函式和程序更簡單、更好讀、也更容易 debug。搭配 log(RAISE NOTICE)和 PostgreSQL 內建診斷函式(像 current_query()),它就是打造穩定、好維護又容易理解系統的好工具。
GO TO FULL VERSION