CodeGym /課程 /SQL SELF /如何在 PL/pgSQL 函式中回傳值

如何在 PL/pgSQL 函式中回傳值

SQL SELF
等級 50, 課堂 1
開放

當你在 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 也會報錯。

2
任務
SQL SELF, 等級 50, 課堂 1
上鎖
用來過濾活躍學生的函式
用來過濾活躍學生的函式
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION