CodeGym /課程 /SQL SELF /函式執行控制:PERFORM

函式執行控制:PERFORM

SQL SELF
等級 55 , 課堂 3
開放

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_stagePERFORM 來記錄每個階段的狀態,讓我們的程式碼更好 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()),它就是打造穩定、好維護又容易理解系統的好工具。

2
任務
SQL SELF, 等級 55, 課堂 3
上鎖
使用 `PERFORM` 調用日誌記錄函數
使用 `PERFORM` 調用日誌記錄函數
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION