當你在 PostgreSQL 裡寫 function,第一個會遇到的問題就是:怎麼回傳結果。有時候你只想回傳一個數字,有時候是一整個 table,甚至有時候還要回傳多個資料集。這一節我們會把所有常見的方式都講一遍:從最簡單的 RETURN 到 RETURN QUERY、RETURNS TABLE 跟 SETOF。
單一結果:RETURN
如果你的 function 只需要回傳一個值——比如總和或資料筆數——就用最基本的 RETURN 就好。
CREATE FUNCTION count_students() RETURNS INT AS $$
DECLARE
total INT;
BEGIN
SELECT COUNT(*) INTO total FROM students;
RETURN total;
END;
$$ LANGUAGE plpgsql;
當你在 PL/pgSQL 裡寫 function,你一定要指定它會回傳什麼。這就是 RETURNS 這個關鍵字的用途,它決定 function 回傳結果的「格式」。所以不管你想回傳一個數字、文字還是整個資料表,都要在 RETURNS 那一行寫清楚。
簡單範例:
CREATE FUNCTION add_numbers(a INT, b INT) RETURNS INT AS $$
BEGIN
RETURN a + b;
END;
$$ LANGUAGE plpgsql;
這裡的 RETURNS INT 就是說這個 function 會回傳一個數字。
回傳單一值
我們先從最簡單的開始——一個只回傳單一值的 function。比如說,計算 students 這個 table 裡有多少學生:
CREATE FUNCTION count_students() RETURNS INT AS $$
DECLARE
total INT;
BEGIN
SELECT COUNT(*) INTO total FROM students; -- 把查詢結果存到 total 變數
RETURN total; -- 回傳結果
END;
$$ LANGUAGE plpgsql;
現在你可以這樣呼叫這個 function:
SELECT count_students(); -- 會回傳學生人數
用 RETURNS TABLE 回傳多個值
有時候你會想回傳不只一個值,而是一整個資料集。比如說,所有學生的 id 跟名字。這時候就可以用 RETURNS TABLE 這個語法。
CREATE FUNCTION get_students() RETURNS TABLE(id INT, name TEXT) AS $$
BEGIN
RETURN QUERY SELECT id, name FROM students; -- 把查詢結果當成 table 回傳
END;
$$ LANGUAGE plpgsql;
現在你可以這樣呼叫這個 function:
SELECT * FROM get_students(); -- 會回傳所有學生的 table
注意 RETURNS TABLE 這幾個字。它就是在說這個 function 會回傳一個有指定欄位(這裡是 id 跟 name)的 table。
使用 RETURN QUERY
你應該已經覺得上面的例子很方便了。不過還有一個重點:RETURN QUERY 是 PL/pgSQL 的魔法棒,可以直接把查詢結果回傳出去。你可以用它回傳整個查詢的結果,或是其中一部分。
假設我們只想回傳那些還在就讀(資料庫裡 active = TRUE)的學生:
CREATE FUNCTION get_active_students() RETURNS TABLE(id INT, name TEXT) AS $$
BEGIN
RETURN QUERY
SELECT id, name
FROM students
WHERE active = TRUE; -- 只回傳 active 的學生
END;
$$ LANGUAGE plpgsql;
現在你可以呼叫這個 function,拿到所有 active 學生的資料:
SELECT * FROM get_active_students();
不用 RETURNS TABLE 回傳多行資料
有時候你可能不想用 RETURNS TABLE,但還是想回傳多行資料。這時候可以用 SETOF 這個型別。它可以讓你回傳一堆結構一樣的資料列。 舉個例子:
CREATE FUNCTION get_student_names() RETURNS SETOF TEXT AS $$
BEGIN
RETURN QUERY
SELECT name
FROM students;
END;
$$ LANGUAGE plpgsql;
這個 function 只會回傳學生的名字清單:
SELECT * FROM get_student_names();
根據輸入參數回傳不同資料
function 不一定只能回傳固定的結果。你可以用參數讓它動態改變回傳內容。
比如說,根據學生 id 回傳資料:
CREATE FUNCTION get_student_by_id(student_id INT) RETURNS TABLE(id INT, name TEXT) AS $$
BEGIN
RETURN QUERY
SELECT id, name
FROM students
WHERE id = student_id; -- 用 student_id 參數
END;
$$ LANGUAGE plpgsql;
現在你可以查詢特定學生的資訊:
SELECT * FROM get_student_by_id(3); -- 會回傳 ID = 3 的學生資料
回傳複雜資料(多個資料集)
有時候資料太複雜,需要回傳多個資料集。這時你可以用 cursor。比如說,你想從 function 回傳兩組資料——active 學生跟 inactive 學生的清單。
CREATE FUNCTION get_students_status() RETURNS SETOF RECORD AS $$
BEGIN
RETURN QUERY
SELECT id, name, 'active' AS status
FROM students
WHERE active = TRUE;
RETURN QUERY
SELECT id, name, 'inactive' AS status
FROM students
WHERE active = FALSE;
END;
$$ LANGUAGE plpgsql;
現在你可以拿到兩組資料:
SELECT * FROM get_students_status();
用 RETURNS 會遇到的常見錯誤
沒寫回傳型別: 如果你沒寫 function 會回傳什麼,PostgreSQL 會直接報錯。像這樣:
CREATE FUNCTION no_return_type() AS $$ -- 錯誤,沒寫 RETURNS
BEGIN
RETURN 1;
END;
$$ LANGUAGE plpgsql;
資料型別不符: 要確定你回傳的資料型別跟宣告的一樣。比如你寫 INT,就不能回傳字串。
忘記用 RETURN QUERY: 如果你要回傳查詢結果但忘了寫 RETURN QUERY,function 會啥都不回傳。
多值回傳寫錯: 如果你想回傳多行資料,但沒用 SETOF 或 TABLE,PostgreSQL 也會報錯。
GO TO FULL VERSION