這堂課我們會看看 PL/pgSQL 支援哪些資料型別,還有怎麼有效率地用它們。我們會重點介紹四種資料型別:
INTEGER用來處理數字。TEXT處理字串。BOOLEAN處理邏輯值。RECORD處理動態資料結構。
每個型別我們都會用範例來說明,讓你看到實際怎麼用。
PL/pgSQL 支援的資料型別
PL/pgSQL 支援你在 PostgreSQL 裡熟悉的所有資料型別。從簡單的數字型別(INTEGER、NUMERIC)到比較複雜的像陣列和 JSONB。我們來快速看一下主要的型別。
基本型別:
INTEGER、BIGINT、FLOAT、NUMERIC— 數字型別。TEXT、CHAR、VARCHAR— 字串型別。BOOLEAN— 邏輯型別。
複雜型別:
RECORD— 處理動態資料集。ROWTYPE— 處理資料表 row 型別。- 陣列跟 JSON — 之後課程會再講。
怎麼用 INTEGER 型別
INTEGER 是最常用的資料型別之一,用來存整數。在 PL/pgSQL 裡你可以用這型別來做計算、處理資料的 id、還有判斷條件。
範例:計算資料筆數
假設我們有一個 students 資料表,想知道有幾個學生在資料庫裡。
DO $$
DECLARE
total_students INTEGER; -- 用來存學生數量的變數
BEGIN
SELECT COUNT(*) INTO total_students FROM students; -- 把查詢結果存進變數
RAISE NOTICE '學生數量:%', total_students; -- 印出訊息
END;
$$;
用 INTEGER 時要注意:
- 在 PL/pgSQL 裡,變數賦值要用
INTO。 - 如果你想把小數存進
INTEGER,會出錯。這種情況要用NUMERIC或FLOAT。
怎麼用 TEXT 型別
TEXT 用來存字串資料。像是名字、描述或其他文字內容都很適合用這型別。
範例:印出學生名字
這個範例會把 students 資料表裡所有學生的名字印出來。
DO $$
DECLARE
student_name TEXT; -- 存學生名字的變數
BEGIN
FOR student_name IN SELECT name FROM students LOOP
RAISE NOTICE '學生名字:%', student_name; -- 印出每個名字
END LOOP;
END;
$$;
處理 TEXT 很實用的函數:
UPPER()跟LOWER()— 轉成大寫/小寫。CONCAT()— 字串合併。LENGTH()— 字串長度。
舉個例子:
DO $$
DECLARE
full_name TEXT;
BEGIN
full_name := CONCAT('阿歷克斯', ' 明'); -- 合併字串
RAISE NOTICE '全名:%', UPPER(full_name); -- 印出大寫名字
END;
$$;
怎麼用 BOOLEAN 型別
BOOLEAN 用來存邏輯值:TRUE、FALSE 跟 NULL。這型別在判斷條件和資料篩選時超好用。
範例:檢查學生是否啟用
假設你有個 students 資料表,裡面有個 is_active 欄位,表示學生是不是啟用狀態。
DO $$
DECLARE
is_active BOOLEAN; -- 存啟用狀態的變數
BEGIN
SELECT is_active INTO is_active FROM students WHERE id = 1; -- 從資料表拿值
IF is_active THEN
RAISE NOTICE '學生是啟用的!';
ELSE
RAISE NOTICE '學生沒啟用。';
END IF;
END;
$$;
用 BOOLEAN 時要注意:
- 邏輯值可以直接用在
IF跟WHILE條件裡。 NULL在邏輯判斷裡是「未定義」,所以檢查時要小心。
怎麼用 RECORD 型別
RECORD 是很強大的型別,用來存沒有預先定義結構的資料 row。當你處理 SQL 查詢結果有多個欄位時,這型別超方便。
範例:走訪資料表所有資料
下面這個範例會走訪 students 資料表的每一筆資料,印出每個學生的名字和 ID。
DO $$
DECLARE
student RECORD; -- 動態 row 型別
BEGIN
FOR student IN SELECT id, name FROM students LOOP
RAISE NOTICE 'ID:%,名字:%', student.id, student.name; -- 取出欄位
END LOOP;
END;
$$;
用 RECORD 時要注意:
RECORD型別的變數只能在迴圈裡或用SELECT INTO查詢時填值。- 欄位要用
record.column_name來取。
用 ROWTYPE 處理整個資料表 row
如果你想把整個資料表的一筆資料存下來(而且想要明確型別),可以用 ROWTYPE。它會自動繼承資料表 row 的結構。
範例:用 ROWTYPE 型別
DO $$
DECLARE
student students%ROWTYPE; -- 跟 students 資料表 row 結構一樣的變數
BEGIN
SELECT * INTO student FROM students WHERE id = 1; -- 把 row 資料存進變數
RAISE NOTICE '學生名字:%,課程:%', student.name, student.course;
END;
$$;
RECORD 跟 ROWTYPE 的差異
| 特性 | RECORD | ROWTYPE |
|---|---|---|
| 欄位結構 | 事先沒定義 | 依資料表或查詢而定 |
| 用途 | 彈性,什麼查詢都能用 | 結構固定,跟資料表綁定 |
實戰範例
我們來寫個函數,回傳啟用中的學生數量和他們的名字。
CREATE FUNCTION active_students_report() RETURNS TABLE(id INT, name TEXT) AS $$
BEGIN
RETURN QUERY
SELECT id, name FROM students WHERE is_active = TRUE;
END;
$$ LANGUAGE plpgsql;
呼叫這個函數:
SELECT * FROM active_students_report();
用資料型別時常見錯誤
有時候處理資料會遇到錯誤,這裡列幾個常見的:
- 型別錯誤:像把字串存進
INTEGER變數(例如my_var := 'abc';)。 - 在需要
TRUE或FALSE的地方用了NULL。 - 沒初始化就用
RECORD。
怎麼避免這些錯誤:
- 變數型別一定要明確寫出來。
- 寫入前先檢查資料表欄位的型別。
- 多用
RAISE NOTICE這種 debug 指令。
現在你已經知道怎麼在 PL/pgSQL 裡用 INTEGER、TEXT、BOOLEAN 跟 RECORD 這些資料型別了。這些知識會讓你寫出更強大、更複雜的 PostgreSQL 程序語言程式!
GO TO FULL VERSION