CodeGym /課程 /SQL SELF /分析常見在控制結構和日誌處理時會犯的錯誤

分析常見在控制結構和日誌處理時會犯的錯誤

SQL SELF
等級 52 , 課堂 4
開放

進入主題之前,先來看看你最有可能遇到的常見錯誤和小疏忽。畢竟 SQL 出錯真的很煩,而且通常都在最不想出錯的時候出現。

1. 語法錯誤:「忘記關閉 IF

語法錯誤是最基本的問題,但比你想像的還常見。比如你忘了用 END IF; 關閉 IF 條件區塊,compiler 馬上就會給你臉色看。

錯誤範例:

CREATE OR REPLACE FUNCTION check_number(num INTEGER)
RETURNS TEXT AS $$
BEGIN
    IF num > 0 THEN
        RETURN 'Positive';
    ELSE
        RETURN 'Negative';
-- somewhere lost END IF;
END;
$$ LANGUAGE plpgsql;

你執行這段 code 會看到錯誤:ERROR: syntax error at or near "END"。為什麼?因為 IF 區塊沒關閉啦。

怎麼避免這種錯?

一定要養成寫 code 有結構的習慣。你開一個區塊(像 IF),馬上就把結束也寫好。來看正確範例:

CREATE OR REPLACE FUNCTION check_number(num INTEGER)
RETURNS TEXT AS $$
BEGIN
    IF num > 0 THEN
        RETURN 'Positive';
    ELSE
        RETURN 'Negative';
    END IF; -- 記得關閉區塊
END;
$$ LANGUAGE plpgsql;

2. CASE 沒處理所有情況:「如果都沒中怎麼辦?」

CASE 時,一定要加 ELSE 處理意外狀況。沒這個分支可能會讓你拿到 NULL,然後 debug 到懷疑人生。

錯誤範例:

CREATE OR REPLACE FUNCTION grade_result(grade CHAR)
RETURNS TEXT AS $$
BEGIN
    RETURN CASE grade
        WHEN 'A' THEN 'Excellent'
        WHEN 'B' THEN 'Good'
        WHEN 'C' THEN 'Average'
        -- 如果 grade = 'D' 或其他分數呢?
    END;
END;
$$ LANGUAGE plpgsql;

如果你傳進去 D,function 會回傳 NULL,這可能會讓你的 code 出問題。

修正版:

CREATE OR REPLACE FUNCTION grade_result(grade CHAR)
RETURNS TEXT AS $$
BEGIN
    RETURN CASE grade
        WHEN 'A' THEN 'Excellent'
        WHEN 'B' THEN 'Good'
        WHEN 'C' THEN 'Average'
        ELSE '未知分數' -- 把其他情況都抓起來
    END;
END;
$$ LANGUAGE plpgsql;

3. 無窮迴圈的問題:「為什麼 server 卡住了?」

LOOP 很容易忘記寫跳出條件,這樣會讓你的 code 一直跑下去:

錯誤範例:

CREATE OR REPLACE FUNCTION infinite_loop_demo()
RETURNS VOID AS $$
DECLARE
    i INTEGER := 1;
BEGIN
    LOOP
        i := i + 1;
        -- 沒有跳出條件!
    END LOOP;
END;
$$ LANGUAGE plpgsql;

這段 code 會讓 server 卡死,因為迴圈永遠不會結束。

怎麼修:

加個 EXIT 跳出條件就好:

CREATE OR REPLACE FUNCTION finite_loop_demo()
RETURNS VOID AS $$
DECLARE
    i INTEGER := 1;
BEGIN
    LOOP
        i := i + 1;
        IF i > 10 THEN
            EXIT; -- 跳出條件
        END IF;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

4. 迴圈漏掉資料:「那漏掉的資料怎麼辦?」

CONTINUE 跳過某些迴圈時,如果沒想清楚所有情況,可能會出錯。例如:

錯誤範例:

CREATE OR REPLACE FUNCTION skip_even()
RETURNS VOID AS $$
DECLARE
    i INTEGER := 0;
BEGIN
    WHILE i < 10 LOOP
        i := i + 1;
        IF i % 2 = 0 THEN
            CONTINUE; -- 直接跳過偶數
        END IF;
        RAISE NOTICE '奇數: %', i;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

如果全部都是偶數呢?server 會跑,但你什麼都看不到。

怎麼修:

記得把所有資料都處理好,加點 log 方便追蹤:

CREATE OR REPLACE FUNCTION skip_even_logging()
RETURNS VOID AS $$
DECLARE
    i INTEGER := 0;
BEGIN
    WHILE i < 10 LOOP
        i := i + 1;
        IF i % 2 = 0 THEN
            RAISE NOTICE '跳過偶數: %', i;
            CONTINUE;
        END IF;
        RAISE NOTICE '奇數: %', i;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

這樣你就知道哪些數字被跳過了。

5. 錯誤處理寫錯:「我的 RAISE EXCEPTION 呢?」

RAISE EXCEPTION 處理錯誤很強大,但寫錯語法就 GG 了。

錯誤範例:

CREATE OR REPLACE FUNCTION calculate_square(num INTEGER)
RETURNS INTEGER AS $$
BEGIN
    IF num < 0 THEN
        RAISE '不允許負數!';
    END IF;
    RETURN num * num;
END;
$$ LANGUAGE plpgsql;

這段 code 會出錯,因為 RAISE 少了訊息等級(要加 EXCEPTION)。

修正版:

CREATE OR REPLACE FUNCTION calculate_square(num INTEGER)
RETURNS INTEGER AS $$
BEGIN
    IF num < 0 THEN
        RAISE EXCEPTION '不允許負數!';
    END IF;
    RETURN num * num;
END;
$$ LANGUAGE plpgsql;

6. log 寫錯:「為什麼我的錯誤沒寫進 error_log?」

error_log table 時,如果 INSERT INTO 寫錯欄位名就會出錯。

錯誤範例:

CREATE OR REPLACE FUNCTION log_error(err_msg TEXT)
RETURNS VOID AS $$
BEGIN
    INSERT INTO error_log (error_message, error_time)
    VALUES (err_msg, CURRENT_TIMESTAMP); -- 如果欄位名改了呢?
END;
$$ LANGUAGE plpgsql;

如果 error_log table 的欄位名被改成 error_msg,這就會出錯。

怎麼避免:

一定要確認 table 結構,或是用嚴格 schema 管理資料。

7. 一般粗心和「人為疏失」

錯誤不只技術問題,還有粗心造成的。像是忘了 debug、不用的變數、沒排版,這些都會讓你的 function 變成一團亂。

範例:

DECLARE
    i INTEGER; -- 幹嘛宣告不用的變數?

修正:把沒用的 code 刪掉,讓 code 乾淨又好懂。

現在你已經準備好避開 PL/pgSQL 最常見的錯誤,寫出讓你開心、bug 少的 code。記得多測試、多 log、bug 早點修——這樣你就能省下很多神經和客戶電話啦!

1
問卷/小測驗
錯誤處理,等級 52,課堂 4
未開放
錯誤處理
錯誤處理
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION