CodeGym /課程 /SQL SELF /錯誤處理:RAISE EXCEPTION

錯誤處理:RAISE EXCEPTION

SQL SELF
等級 52 , 課堂 0
開放

想像一下,你寫了一個 function 要算學生的平均分數。如果你不小心除以零(比如沒成績),會發生什麼事?這種 code 如果直接丟到 production,bug 馬上就來敲門啦。PL/pgSQL 有很強大的錯誤處理工具,讓你的 code 更穩、更安全,也更好維護。

PL/pgSQL 的錯誤處理可以:

  1. 產生訊息,說明哪裡出錯。
  2. 遇到嚴重錯誤時直接中止執行。
  3. 把問題記錄下來,方便之後分析。

PL/pgSQL 的訊息等級

PL/pgSQL 支援幾種訊息等級,幫助開發者 debug 跟排除問題。如下:

  • NOTICE:顯示資訊訊息,通常用來 debug。
  • WARNING:提醒有潛在問題,但不會中斷程式。
  • EXCEPTION:嚴重錯誤,會中止程式(然後把控制權還給呼叫端)。

PL/pgSQL 的訊息等級

訊息等級 說明
NOTICE 資訊或 debug 訊息,不影響執行
WARNING 可能有問題的提醒,像提示一樣
EXCEPTION 嚴重錯誤,會終止程式執行

RAISE 指令語法

要產生訊息或處理錯誤,用 RAISE 指令。基本語法如下:

RAISE <訊息等級> '訊息內容' [, 變數...];
  • <訊息等級>NOTICEWARNINGEXCEPTION
  • '訊息內容' — 問題描述。
  • [變數...] — 可以插入訊息內容的變數。

範例 1:用 RAISE NOTICE

有時候你想知道 function 裡面發生什麼事。比如 debug 迴圈:

DO $$
BEGIN
    FOR i IN 1..5 LOOP
        RAISE NOTICE '目前 i 的值: %', i;
    END LOOP;
END
$$;

結果:console 會顯示 目前 i 的值: 1目前 i 的值: 2,一直到 5。

範例 2:用 RAISE EXCEPTION

假設你寫一個 function,遇到某些狀況就要直接報錯:

DO $$
BEGIN
    IF 1 = 1 THEN
        RAISE EXCEPTION '有什麼地方怪怪的!';
    END IF;
END
$$;

結果:執行會中斷,錯誤訊息會顯示在 console。

RAISE 裡用參數

你可以用參數讓訊息內容更個人化。用 % 當 placeholder:

範例 3:在 RAISE 插入變數

DO $$
DECLARE
    student_name TEXT := '伊凡';
    average_score NUMERIC := NULL;
BEGIN
    IF average_score IS NULL THEN
        RAISE EXCEPTION '學生 % 沒有平均分數!', student_name;
    END IF;
END
$$;

結果:訊息 學生 伊凡 沒有平均分數!

你看,% 會被 student_name 取代,讓訊息更有意義。

自訂錯誤產生

錯誤不一定是意外!有時候你要故意產生錯誤,保護 code 不被錯的資料搞壞。

範例 4:檢查輸入值

寫個 function,檢查數字是不是負的,如果是就報錯:

CREATE OR REPLACE FUNCTION check_positive(value NUMERIC)
RETURNS TEXT AS $$
BEGIN
    IF value < 0 THEN
        RAISE EXCEPTION '數字 % 是負的!', value;
    END IF;
    RETURN '數字沒問題。';
END;
$$ LANGUAGE plpgsql;

來測試 function:

SELECT check_positive(-5);

結果:錯誤訊息 數字 -5 是負的!

如果傳正數:

SELECT check_positive(10);

結果數字沒問題。

錯誤處理的情境

你會產生錯誤已經很棒了,更厲害的是根據情況處理錯誤。這時就要用 BEGIN ... EXCEPTION 區塊。

錯誤處理結構

BEGIN
    -- 你的主要程式碼
EXCEPTION
    WHEN 錯誤類型 THEN
        -- 發生這個錯誤要做什麼
    WHEN 其他錯誤 THEN
        -- 發生其他錯誤要做什麼
    WHEN OTHERS THEN
        -- 處理所有沒特別寫的錯誤
END;

來解釋一下:

  • EXCEPTION — 關鍵字,表示開始處理錯誤。
  • WHEN — 指定要處理哪種錯誤,例如 unique_violationdivision_by_zero
  • OTHERS — 處理所有沒特別寫的錯誤。

範例 5:處理除以零

來個簡單的除法 function,示範錯誤處理:

CREATE OR REPLACE FUNCTION safe_divide(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
    -- 嘗試做除法
    RETURN a / b;
EXCEPTION
    WHEN division_by_zero THEN
        RAISE WARNING '試圖除以零,回傳 NULL。';
        RETURN NULL;
END;
$$ LANGUAGE plpgsql;

測試 function:

SELECT safe_divide(10, 2);  -- 預期結果:5
SELECT safe_divide(10, 0);  -- 預期結果:NULL,console 會有警告

RAISE 常見錯誤

忘記寫訊息等級。 如果你沒寫等級,PostgreSQL 會報錯。

錯誤寫法:

RAISE '沒有等級的訊息';

正確寫法:

RAISE NOTICE '有 NOTICE 等級的訊息';

參數錯誤。 如果你用了 %,記得要給對應數量的變數。

錯誤寫法:

RAISE NOTICE '參數範例 %';

正確寫法:

RAISE NOTICE '參數範例 %', '值';

打斷流程。 RAISE EXCEPTION 用太多會讓重要操作被中斷,要用得剛剛好。

實用小技巧

  1. 小心用 WHEN OTHERS 能寫明確錯誤就寫,避免把該特別處理的錯誤都吃掉。
  2. RAISE 來 debug。 千萬不要讓錯誤沒被處理。
  3. 記得效能。 錯誤處理會有成本,特別是大程序。

如果你都做對了,你的程序就會超穩,連突發狀況都能撐住。PM 看到一定超級 proud of you!

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION