CodeGym /課程 /SQL SELF /PL/pgSQL 語法基礎

PL/pgSQL 語法基礎

SQL SELF
等級 49 , 課堂 3
開放

我們來更深入玩玩 PL/pgSQL,開始更積極地用它吧。

程式區塊

PL/pgSQL 的程式區塊就是這語言的主幹啦。可以說它是我們 function、procedure 跟其他魔法的骨架。區塊負責執行邏輯、處理資料、錯誤管理,全部都包在同一個「容器」裡。

PL/pgSQL 的區塊有結構,主要分三個部分:

  1. DECLARE:宣告變數(可選)。
  2. BEGIN ... END:主要執行區塊,邏輯都在這裡跑。
  3. EXCEPTION:錯誤處理(可選)。

如果你喜歡比喻:想像一下做菜的食譜。雖然食譜一開始會列材料,真正的魔法還是在烹飪過程裡。用 PL/pgSQL 的語言來說:

  • DECLARE — 就是材料清單(變數)。
  • BEGIN ... END — 就是混合、煎、煮的地方。
  • EXCEPTION — 就是如果燒焦了要怎麼辦的備案。

PL/pgSQL 區塊語法

先來看一下區塊的基本結構,就像「骨架」一樣。之後我們再加點肉(或你愛的素起司)——也就是實際的邏輯。

DO $$
DECLARE
    -- 這裡宣告變數
    student_count INT;
BEGIN
    -- 這裡執行邏輯
    SELECT COUNT(*) INTO student_count FROM students;
    RAISE NOTICE '學生總數: %', student_count;
EXCEPTION
    -- 這裡處理錯誤
    WHEN OTHERS THEN
        RAISE NOTICE '發生錯誤。';
END;
$$;

我們來一步一步拆解這個例子。

  1. DECLARE — 這裡宣告我們的變數。超讚的是,PL/pgSQL 幾乎支援 PostgreSQL 所有的資料型態,從基本的 INTEGER 到很酷的 JSONB 都有。要宣告變數,只要寫名字、型態,還有需要的話可以給初始值。

範例:

DECLARE
    student_name TEXT;    -- 學生名字的變數
    course_count INT := 0; -- 初始值設為 0
    is_graduated BOOLEAN; -- 布林變數

注意,變數可以有初始值(像 course_count),也可以沒有。

  1. BEGIN ... END — 主要執行區塊。

這部分負責執行主要邏輯。你可以:

  • 執行 SQL 查詢(SELECTINSERT 等等)。
  • 操作資料。
  • 用控制結構(IFLOOP 等等)。
  • RAISE 印出 debug 訊息。

範例:

BEGIN
    SELECT COUNT(*) INTO student_count FROM students;
    IF student_count > 0 THEN
        RAISE NOTICE '我們有學生!';
    ELSE
        RAISE NOTICE '找不到學生。';
    END IF;
END;
  1. EXCEPTION — 錯誤處理(可選)。

如果執行區塊時出錯,EXCEPTION 區段可以讓你攔截錯誤,做點有用的事——像是印出訊息或執行備用程式碼。

範例:

BEGIN
    SELECT COUNT(*) INTO student_count FROM non_existing_table; -- 錯誤!
EXCEPTION
    WHEN OTHERS THEN
        RAISE NOTICE '哎呀,出錯啦!';
END;

實戰範例:計算學生數量

現在我們把所有部分組合起來,做個實用的例子。寫一個 PL/pgSQL 區塊,計算 students 表裡的學生數,然後印出訊息。

DO $$
DECLARE
    total_students INT; -- 存學生數的變數
BEGIN
    -- 計算學生數
    SELECT COUNT(*) INTO total_students FROM students;

    -- 印出結果訊息
    RAISE NOTICE '學生人數: %', total_students;
EXCEPTION
    -- 處理可能的錯誤,例如表不存在
    WHEN OTHERS THEN
        RAISE NOTICE '計算學生數時發生錯誤。';
END;
$$;

執行這個區塊會在 console 印出訊息。例如:學生人數: 42

變數使用小細節

來看幾個重要的點:

給變數賦值。 要把資料存進變數,可以用 SELECT INTO

SELECT COUNT(*) INTO total_students FROM students;

變數初始化。 如果你宣告變數時沒給值,預設就是 NULL

例如:

DECLARE
    my_var INT; -- 預設值是 NULL

RECORD 型態的變數。 這是很萬用的變數型態,可以存一整行資料。範例:

DECLARE
    student RECORD;
BEGIN
    SELECT * INTO student FROM students WHERE id = 1;
    RAISE NOTICE '學生名字: %, 年齡: %', student.name, student.age;
END;

範例:計算學生的課程數

來解個實用問題:算出某個學生修了幾門課,然後印出來。

DO $$
DECLARE
    student_id INT := 1;   -- 學生 ID
    course_count INT;      -- 課程數的變數
BEGIN
    -- 計算課程數
    SELECT COUNT(*) INTO course_count
    FROM enrollments
    WHERE student_id = student_id;

    -- 印出訊息
    RAISE NOTICE '學生 ID % 修了 % 門課。', student_id, course_count;
EXCEPTION
    WHEN OTHERS THEN
        RAISE NOTICE '處理學生 ID % 時發生錯誤', student_id;
END;
$$;

這個區塊很彈性:你可以改 student_id,查不同學生修了幾門課。

錯誤與避免方法

如果你覺得 PL/pgSQL 在你心裡像微波爐裡的小熱狗亂跳,這很正常。剛開始常常會遇到「經典」錯誤。這裡舉幾個例子:

沒宣告變數。 如果你忘了用 DECLARE 宣告變數,PL/pgSQL 會報錯說變數「不存在」。

NULL 當值。 如果變數宣告了但沒給值,預設就是 NULL。這可能會讓程式怪怪的。例如:

IF my_var = NULL THEN -- 不會動!

要用 IS NULL

IF my_var IS NULL THEN

錯誤用法的 EXCEPTION 區段。 有時候工程師會攔所有錯誤(WHEN OTHERS),但沒寫要做什麼。這樣會把真正的問題藏起來。最好還是印出錯誤訊息:

RAISE NOTICE '錯誤: %', SQLERRM;
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION