Trong PostgreSQL, function là một công cụ mạnh mẽ giúp tự động hóa công việc, xây dựng business logic và làm cho server thông minh hơn. Hãy tưởng tượng function như những mini-program chạy bên trong database. Nó tiện cho:
- Tái sử dụng code. Nếu bạn phải lặp lại cùng một truy vấn nhiều lần, hãy gói nó vào function và gọi khi cần.
- Tự động hóa task. Ví dụ, bạn cần tính lương cho nhân viên dựa trên số giờ làm việc. Function xử lý ngon lành luôn.
- Đóng gói logic. Cho phép để các phép tính phức tạp ở phía server, client không phải đau đầu với SQL query nữa.
Cú pháp tổng quát CREATE FUNCTION
Đây là cấu trúc cơ bản để tạo function:
CREATE FUNCTION function_name(parameters) RETURNS return_type AS $$
BEGIN
-- Thân function (logic)
RETURN kết_quả;
END;
$$ LANGUAGE plpgsql;
Cùng phân tích các phần chính:
CREATE FUNCTION function_name(parameters):
Dòng này mình đặt tên function là function_name và truyền tham số (nếu cần).
Tham số có thể gồm tên và kiểu dữ liệu: my_param INTEGER, another_param TEXT.
RETURNS return_type:
Chỉ định function sẽ trả về gì: một giá trị (INTEGER, TEXT v.v.) hay một tập dữ liệu (TABLE, RECORD).
BEGIN ... END:
Bên trong hai từ khóa này là "thân" function, nơi mọi phép thuật diễn ra.
RETURN kết_quả:
Trả về kết quả thực thi function. Lưu ý: kiểu kết quả phải đúng với cái bạn đã ghi ở RETURNS.
LANGUAGE plpgsql:
Chỉ định dùng ngôn ngữ PL/pgSQL. PostgreSQL còn hỗ trợ nhiều ngôn ngữ khác, nhưng giờ mình chỉ cần cái này thôi.
Ví dụ đơn giản: cộng hai số
Cùng tạo function trả về tổng của hai số nguyên nhé.
CREATE FUNCTION add_numbers(a INT, b INT) RETURNS INT AS $$
BEGIN
RETURN a + b;
END;
$$ LANGUAGE plpgsql;
Giờ gọi thử nó nè:
SELECT add_numbers(5, 7); -- Kết quả: 12
Có gì ở đây nhỉ?
- Function nhận hai tham số
avàbkiểuINT. - Bên trong function, mình chỉ việc cộng lại (
a + b) rồi trả về kết quả. - Dễ như dùng máy tính luôn!
Ví dụ dùng biến trong function
Giả sử bạn có database trường đại học và muốn biết có bao nhiêu sinh viên đã đăng ký.
Tạo function nhé:
CREATE FUNCTION count_students() RETURNS INT AS $$
DECLARE
total INT; -- Khai báo biến để lưu kết quả
BEGIN
SELECT COUNT(*) INTO total FROM students; -- Đếm số dòng trong bảng
RETURN total; -- Trả về kết quả
END;
$$ LANGUAGE plpgsql;
Gọi function:
SELECT count_students(); -- Giả sử kết quả: 120
Ở đây bạn thấy:
- Dùng biến
totalđể lưu kết quả truy vấn SQL. - Lệnh
SELECT ... INTOghi kết quả truy vấn vào biến.
Cách này rất tiện nếu bạn cần xử lý dữ liệu trước rồi mới trả về.
Trả về nhiều giá trị: RETURNS TABLE
Ví dụ trước chỉ trả về một giá trị. Nhưng nếu function cần trả về một tập dữ liệu, ví dụ danh sách sinh viên thì sao? Đây là lúc RETURNS TABLE phát huy tác dụng.
Ví dụ:
CREATE FUNCTION get_students() RETURNS TABLE(id INT, name TEXT) AS $$
BEGIN
RETURN QUERY SELECT id, name FROM students;
END;
$$ LANGUAGE plpgsql;
Gọi function:
SELECT * FROM get_students();
Kết quả có thể là:
| id | name |
|---|---|
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
Lợi ích của RETURN QUERY khi chạy query trong function
RETURN QUERY cho phép trả về kết quả truy vấn SQL trực tiếp từ function. Như vậy đỡ phải qua nhiều bước trung gian, function cũng gọn hơn.
Tạo function trả về sinh viên đang active nhé:
CREATE FUNCTION get_active_students() RETURNS TABLE(id INT, name TEXT) AS $$
BEGIN
RETURN QUERY SELECT id, name FROM students WHERE active = TRUE;
END;
$$ LANGUAGE plpgsql;
Trước khi gọi function get_active_students(), bạn cần tạo bảng students và thêm dữ liệu test. Làm như sau:
-- Tạo bảng sinh viên
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
active BOOLEAN DEFAULT TRUE
);
-- Thêm vài dòng dữ liệu
INSERT INTO students (name, active) VALUES
('Alice', FALSE),
('Bob', TRUE),
('Charlie', TRUE),
('Dana', FALSE);
Bảng:
| id | name | active |
|---|---|---|
| 1 | Alice | false |
| 2 | Bob | true |
| 3 | Charlie | true |
| 4 | Dana | false |
Giờ gọi thử:
SELECT * FROM get_active_students();
Kết quả:
| id | name |
|---|---|
| 2 | Bob |
| 3 | Charlie |
Kiểm tra dữ liệu trước khi thực thi
Function có thể chứa kiểm tra IF để đảm bảo dữ liệu hợp lệ. Ví dụ, mình có thể tạo function chuyển sinh viên lên khóa mới chỉ khi bạn ấy đã qua hết các kỳ thi.
Ví dụ:
CREATE FUNCTION promote_student(student_id INT) RETURNS TEXT AS $$
DECLARE
passed_exams INT;
BEGIN
-- Đếm số kỳ thi đã qua của sinh viên
SELECT COUNT(*) INTO passed_exams
FROM exams
WHERE student_id = promote_student.student_id AND status = 'passed';
-- Kiểm tra điều kiện
IF passed_exams < 5 THEN
RETURN 'Sinh viên chưa qua đủ kỳ thi';
END IF;
-- Cập nhật khóa học của sinh viên
UPDATE students
SET course = course + 1
WHERE id = promote_student.student_id;
RETURN 'Sinh viên đã được lên khóa!';
END;
$$ LANGUAGE plpgsql;
Các lỗi thường gặp khi tạo function
Thiếu kiểu trả về. PostgreSQL luôn yêu cầu bạn chỉ rõ function trả về gì. Ví dụ:
CREATE FUNCTION fail() AS $$ -- Lỗi: thiếu RETURNS
BEGIN
RETURN 1;
END;
$$ LANGUAGE plpgsql;
Sửa lại:
CREATE FUNCTION succeed() RETURNS INT AS $$
BEGIN
RETURN 1;
END;
$$ LANGUAGE plpgsql;
Kiểu trả về không khớp. Nếu bạn ghi RETURNS INT thì phải trả về số. Trả về chuỗi trong trường hợp này là sai nhé.
Lỗi trong SQL query bên trong function. Luôn kiểm tra query trước khi dùng trong function. Tốt nhất là test "bằng tay" qua psql hoặc pgAdmin.
GO TO FULL VERSION