PL/SQL - 異常處理:初學者指南

您好,未來的 PL/SQL 大師!今天,我們將深入探索 PL/SQL 中異常的迷人世界。別擔心如果你是編程新手——我會一步步引導你了解這個主題,就像我這些年來為無數學生所做的那樣。所以,來一杯咖啡(或者茶,如果你喜歡的話),讓我們一起踏上這次令人興奮的旅程吧!

PL/SQL - Exceptions

異常是什麼?

在我們深入細節之前,讓我們先了解什麼是異常。想像你正在烤蛋糕(跟著我,我保證這和編程有關)。你一步步按照配方進行,但突然你發現沒有雞蛋了!這個意外的情況與編程中的異常相似。

在 PL/SQL 中,異常是打擾程序正常流程的意外事件。它可以是像嘗試除以零或嘗試將重複的值插入唯一列中的錯誤。我們可以「處理」這些問題,而不是讓它們使我們的程序崩潰——就像我們在烤蛋糕的比喻中可能會使用雞蛋的替代品一樣。

異常處理的語法

現在,讓我們看看如何在 PL/SQL 中實際處理這些異常。基本結構如下:

BEGIN
-- 你的正常代碼放在這裡
EXCEPTION
WHEN 異常名稱1 THEN
-- 處理異常 1
WHEN 異常名稱2 THEN
-- 處理異常 2
WHEN OTHERS THEN
-- 處理所有其他異常
END;

讓我們分解一下:

  1. 我們在 BEGIN �塊中寫我們的正常代碼。
  2. 如果發生異常,程序會跳轉到 EXCEPTION 塊。
  3. 我們可以使用 WHEN 子句處理特定的異常。
  4. WHEN OTHERS 子句捕獲我們未特別處理的任何異常。

這裡有一個簡單的例子:

DECLARE
v_result NUMBER;
BEGIN
v_result := 10 / 0;  -- 這會引起除以零的錯誤
DBMS_OUTPUT.PUT_LINE('結果: ' || v_result);
EXCEPTION
WHEN ZERO_DIVIDE THEN
DBMS_OUTPUT.PUT_LINE('錯誤:不能除以零!');
END;

在這個例子中,我們試圖將 10 除以 0,這在數學上是不可行的。我們的程序不是崩潰,而是捕獲了 ZERO_DIVIDE 異常,並打印出一個友好的錯誤信息。

抛出異常

有時候,當滿足某些條件時,我們想要創建自己的異常。這就像在足球比賽中當裁判——你看到犯規,你就吹哨!

這是怎麼工作的:

DECLARE
v_age NUMBER := 15;
BEGIN
IF v_age < 18 THEN
RAISE_APPLICATION_ERROR(-20001, '必須年滿 18 歲或以上');
END IF;
DBMS_OUTPUT.PUT_LINE('歡迎來到俱樂部!');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('錯誤: ' || SQLERRM);
END;

在這個例子中,我們正在檢查某人是否有足夠年齡進入俱樂部。如果他們未滿 18 歲,我們會引發一個帶有自定義錯誤信息的異常。WHEN OTHERS 子句捕獲此異常並打印錯誤信息。

用戶定義的異常

雖然 PL/SQL 提供了很多預定義的異常,但有時我們需要創建自己的。這就像在我們的遊戲中創造一個新規則。這是我們如何做到的:

DECLARE
e_invalid_name EXCEPTION;
v_name VARCHAR2(50) := 'J0hn';
BEGIN
IF NOT REGEXP_LIKE(v_name, '^[A-Za-z]+$') THEN
RAISE e_invalid_name;
END IF;
DBMS_OUTPUT.PUT_LINE('名稱有效: ' || v_name);
EXCEPTION
WHEN e_invalid_name THEN
DBMS_OUTPUT.PUT_LINE('錯誤:名稱應只包含字母');
END;

在這個例子中,我們創建了一個自定義異常 e_invalid_name。如果名稱包含除字母以外的任何東西,我們就引發這個異常。這讓我們能夠以對我們程序有意义的 方式處理這個特定情況。

預定義異常

PL/SQL 提供了一套預定義的異常,用於常見的錯誤情況。這就像準備一個急救包以應對常見的傷害。以下是一些最常用的:

異常名稱 描述
NO_DATA_FOUND 當 SELECT INTO 語句返回無行時引發
TOO_MANY_ROWS 當 SELECT INTO 語句返回多於一行時引發
ZERO_DIVIDE 當嘗試除以零時引發
DUP_VAL_ON_INDEX 當嘗試在唯一索引中插入重複值時引發
VALUE_ERROR 當發生算術、轉換、截斷或大小約束錯誤時引發

讓我們看一個使用預定義異常的例子:

DECLARE
v_emp_name VARCHAR2(50);
BEGIN
SELECT first_name INTO v_emp_name
FROM employees
WHERE employee_id = 1000;  -- 假設這個 ID 不存在

DBMS_OUTPUT.PUT_LINE('員工名稱: ' || v_emp_name);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('錯誤:找不到該 ID 的員工');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('錯誤:找到多於一個員工');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('發生了意外的錯誤:' || SQLERRM);
END;

在這個例子中,我們試圖獲取一個員工的名稱。如果找不到員工,我們捕獲 NO_DATA_FOUND 異常。如果不知何故找到多於一個員工,我們捕獲 TOO_MANY_ROWS 異常。任何其他意外錯誤都被 WHEN OTHERS 子句捕獲。

這就是 PL/SQL 中異常處理的基本知識!記住,處理異常就像繫安全帶一樣——當一切順利時,它可能看起來不是必需的,但當事情變得複雜時,它可能會拯救你於麻煩之中。

練習這些概念,嘗試不同的情節,很快你就能像專家一樣處理異常了。快樂編程,願你的程序總能優雅地處理意外!

Credits: Image by storyset