Khi bạn viết function trong PostgreSQL, một trong những việc đầu tiên là hiểu làm sao trả về kết quả. Đôi khi chỉ cần trả về một con số thôi. Đôi khi lại là cả một bảng. Có lúc còn phải trả về nhiều tập dữ liệu khác nhau nữa. Ở phần này, mình sẽ giải thích hết các kiểu cơ bản: từ RETURN đơn giản cho tới RETURN QUERY, RETURNS TABLE và SETOF.
Một kết quả: RETURN
Nếu function của bạn chỉ cần trả về một giá trị thôi — ví dụ tổng hoặc số lượng dòng — thì cứ dùng RETURN bình thường nhé.
CREATE FUNCTION count_students() RETURNS INT AS $$
DECLARE
total INT;
BEGIN
SELECT COUNT(*) INTO total FROM students;
RETURN total;
END;
$$ LANGUAGE plpgsql;
Khi bạn tạo function trong PL/pgSQL, bạn phải chỉ rõ nó sẽ trả về gì. Đó là ý nghĩa của từ khóa RETURNS, nó định nghĩa "kiểu" kết quả mà function trả về. Nên nếu bạn muốn trả về một số, một chuỗi hay một bảng dữ liệu — tất cả đều phải ghi ở dòng RETURNS nhé.
Ví dụ đơn giản:
CREATE FUNCTION add_numbers(a INT, b INT) RETURNS INT AS $$
BEGIN
RETURN a + b;
END;
$$ LANGUAGE plpgsql;
Ở đây từ khóa RETURNS INT cho biết function sẽ trả về một số nguyên.
Trả về một giá trị
Bắt đầu với cái đơn giản nhất — function trả về một giá trị. Ví dụ, function đếm số sinh viên trong bảng students:
CREATE FUNCTION count_students() RETURNS INT AS $$
DECLARE
total INT;
BEGIN
SELECT COUNT(*) INTO total FROM students; -- Lưu kết quả truy vấn vào biến total
RETURN total; -- Trả về kết quả
END;
$$ LANGUAGE plpgsql;
Bây giờ bạn có thể gọi function này:
SELECT count_students(); -- Sẽ trả về số lượng sinh viên
Trả về nhiều giá trị với RETURNS TABLE
Đôi khi bạn cần trả về không chỉ một giá trị mà là cả một tập bản ghi. Ví dụ, danh sách tất cả sinh viên với tên và id của họ. Lúc này dùng RETURNS TABLE nhé.
CREATE FUNCTION get_students() RETURNS TABLE(id INT, name TEXT) AS $$
BEGIN
RETURN QUERY SELECT id, name FROM students; -- Trả về kết quả truy vấn dạng bảng
END;
$$ LANGUAGE plpgsql;
Bây giờ bạn có thể gọi function này:
SELECT * FROM get_students(); -- Sẽ trả về bảng chứa tất cả sinh viên
Lưu ý từ khóa RETURNS TABLE. Nó cho biết function sẽ trả về một bảng với các cột được chỉ định (id và name trong ví dụ này).
Dùng RETURN QUERY
Chắc bạn cũng thích ví dụ trên rồi nhỉ. Nhưng còn một chi tiết nữa: RETURN QUERY — kiểu như cây đũa thần của PL/pgSQL, cho phép trả về dữ liệu trực tiếp từ truy vấn. Nhờ nó bạn có thể trả về kết quả của cả một truy vấn hoặc chỉ một phần của nó.
Giả sử bạn muốn trả về tất cả sinh viên đang học (trạng thái trong database là 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; -- Chỉ trả về sinh viên đang học
END;
$$ LANGUAGE plpgsql;
Bây giờ bạn có thể gọi function và lấy dữ liệu sinh viên đang học:
SELECT * FROM get_active_students();
Trả về nhiều dòng mà không dùng RETURNS TABLE
Có lúc bạn muốn trả về các dòng dữ liệu mà không cần RETURNS TABLE. Khi đó dùng kiểu dữ liệu SETOF. Nó cho phép trả về các dòng cùng cấu trúc. Ví dụ:
CREATE FUNCTION get_student_names() RETURNS SETOF TEXT AS $$
BEGIN
RETURN QUERY
SELECT name
FROM students;
END;
$$ LANGUAGE plpgsql;
Function này chỉ trả về danh sách tên sinh viên:
SELECT * FROM get_student_names();
Trả về giá trị tùy theo tham số đầu vào
Function không phải lúc nào cũng trả về kết quả tĩnh. Nó có thể dùng tham số để thay đổi kết quả động.
Ví dụ trả về dữ liệu theo id sinh viên
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; -- Dùng tham số student_id
END;
$$ LANGUAGE plpgsql;
Bây giờ bạn có thể lấy thông tin một sinh viên cụ thể:
SELECT * FROM get_student_by_id(3); -- Sẽ trả về dữ liệu sinh viên có ID = 3
Trả về dữ liệu phức tạp (nhiều tập)
Có lúc dữ liệu phức tạp đến mức phải trả về nhiều tập. Khi đó bạn có thể dùng cursor. Ví dụ, bạn muốn trả về hai tập dữ liệu từ function — danh sách sinh viên đang học và không học.
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;
Bây giờ bạn có thể lấy cả hai tập dữ liệu:
SELECT * FROM get_students_status();
Lỗi thường gặp khi dùng RETURNS
Không chỉ rõ kiểu trả về: Nếu bạn không ghi rõ function trả về gì, PostgreSQL sẽ báo lỗi. Ví dụ:
CREATE FUNCTION no_return_type() AS $$ -- Lỗi, chưa ghi RETURNS
BEGIN
RETURN 1;
END;
$$ LANGUAGE plpgsql;
Kiểu dữ liệu không khớp: nhớ đảm bảo giá trị trả về đúng kiểu đã khai báo. Ví dụ, nếu bạn ghi INT thì đừng trả về chuỗi nhé.
Quên dùng RETURN QUERY: nếu bạn quên dùng RETURN QUERY cho truy vấn phức tạp, function sẽ không trả về gì cả.
Trả về nhiều giá trị sai cách: nếu bạn trả về dòng dữ liệu mà quên dùng SETOF hoặc TABLE, PostgreSQL sẽ báo lỗi.
GO TO FULL VERSION