Trong nhiều ngôn ngữ lập trình, function và procedure gần như không khác gì nhau. Nhưng trong SQL thì khác nha. Ở PostgreSQL, function và procedure — không chỉ là hai cách chạy code khác nhau. Đây là hai kiểu tư duy khác nhau.
Function trong SQL không thể thay đổi dữ liệu trong database. Nó chỉ được phép làm việc với dữ liệu truyền vào và trả về kết quả dựa trên đó. Nó được tạo ra để dùng trong các truy vấn SELECT.
Procedure trong SQL được tạo ra để thay đổi database. Vì vậy nó có thể làm việc với transaction (khác với function), ghi dữ liệu vào database. Và không thể dùng trong SELECT.
So sánh nhanh nè:
| Đặc điểm | Function (FUNCTION) | Procedure (PROCEDURE) |
|---|---|---|
| Trả về dữ liệu | ✅ Có (RETURNS ...) |
❌ Không (chỉ thực hiện hành động) |
| Gọi qua | SELECT, PERFORM |
CALL |
| Có thể dùng trong truy vấn | ✅ Có | ❌ Không |
Có thể trong DO |
✅ Có | ❌ Không |
Hỗ trợ COMMIT, ROLLBACK |
❌ Không | ✅ Có |
| Có trong PostgreSQL từ | Từ đầu luôn | Từ phiên bản 11 |
Khác biệt trong SQL
Trong SQL thông thường, function giống như một biểu thức: nó tính toán và trả về giá trị. Procedure — là câu lệnh: nó làm gì đó, nhưng không tham gia vào biểu thức.
Function trong SQL
SELECT calculate_discount(200);
- Có thể dùng trong
WHERE,ORDER BY,INSERT,UPDATEv.v. - Phải là pure: không được thay đổi trạng thái database (nếu IMMUTABLE/STABLE).
Procedure trong SQL
CALL process_order(123);
- Không trả về kết quả.
- Có thể làm
COMMIT,ROLLBACK, gọiRAISE, chạy vòng lặp.
Khác biệt trong PL/pgSQL
Function trong PostgreSQL có thể coi như nhóm các phép tính. Rất linh hoạt: truyền tham số, dùng if, vòng lặp, cursor, subquery, trả về dòng, scalar, bảng.
Function trong PL/pgSQL
CREATE FUNCTION square(x INT) RETURNS INT AS $$
BEGIN
RETURN x * x;
END;
$$ LANGUAGE plpgsql;
Đặc điểm:
- Bắt buộc phải có
RETURNS - Có thể dùng
DECLARE,BEGIN,END,LOOP,IF,CASE - Không được thực hiện
COMMIT/ROLLBACK - Có thể gọi trong
SELECT,UPDATE,CHECK,WHERE,RETURNING
Gọi:
SELECT square(5); -- sẽ trả về 25
Procedure trong PL/pgSQL
Procedure — là cơ chế điều khiển hành động. Rất hợp khi bạn cần:
- thực hiện nhiều bước logic;
- update và insert lượng lớn dữ liệu;
- dùng quản lý transaction:
COMMIT,ROLLBACK,SAVEPOINT.
CREATE PROCEDURE log_event(msg TEXT) AS $$
BEGIN
INSERT INTO logs(message) VALUES (msg);
COMMIT;
END;
$$ LANGUAGE plpgsql;
Đặc điểm:
- Không có
RETURNS - Chỉ gọi qua
CALL - Được phép dùng
COMMIT,ROLLBACK,SAVEPOINT - Hợp cho batch processing, migration, ETL
Gọi:
CALL log_event('Xử lý đã xong');
Tại sao function và procedure lại tách biệt
Bởi vì chúng có mục đích khác nhau trong SQL:
| Function | Procedure |
|---|---|
| "Tính toán gì đó và trả về" | "Làm gì đó và không trả về kết quả" |
| Gọi từ SQL | Gọi như command |
| Không thể quản lý transaction | Có thể quản lý transaction |
Dùng trong SELECT, JOIN, WHERE |
Dùng trong CALL, script |
Lợi thế chính của procedure — COMMIT
Procedure có thể quản lý transaction bên trong nó. Tức là ngay trong procedure bạn có thể làm:
BEGIN;
-- logic
SAVEPOINT point1;
-- thử update
ROLLBACK TO point1;
COMMIT;
Còn trong function thì COMMIT và ROLLBACK bị cấm. Nếu bạn thử — sẽ nhận được: ERROR: invalid transaction termination in function
Điều này có nghĩa là function phải luôn deterministic và an toàn, còn procedure thì có thể làm "dirty job" — dọn dẹp, log, insert.
Bảng so sánh
| Đặc điểm | FUNCTION |
PROCEDURE |
|---|---|---|
| Trả về giá trị | ✅ RETURNS |
❌ |
Dùng trong SELECT |
✅ | ❌ |
| Gọi | SELECT, PERFORM, DO |
Chỉ CALL |
| Có thể dùng trong trigger | ✅ | ❌ (chỉ function thôi) |
Transaction bên trong (COMMIT) |
❌ Cấm | ✅ Được phép |
| Dùng OUT-parameter | Qua RETURNS TABLE, RECORD |
Qua OUT-parameter trực tiếp |
| Hợp cho tính toán | ✅ | 🚫 không dành cho |
| Hợp cho ETL, import | 🚫 hạn chế | ✅ tuyệt vời |
| Có thể dùng cursor | ✅ Có | ✅ Có |
Dùng cái nào ở đâu?
Dùng function nếu:
- muốn trả về giá trị;
- gọi trong
SELECT, lọc dữ liệu; - đây là phép tính đơn giản, kiểm tra hoặc wrapper cho SQL.
Dùng procedure nếu:
- muốn thực hiện thao tác phức tạp;
- cần kiểm soát transaction;
- xử lý batch, chuyển dữ liệu, lưu trữ, log.
GO TO FULL VERSION