Trong bài này tụi mình sẽ xem thử PL/pgSQL hỗ trợ những kiểu dữ liệu nào và học cách làm việc hiệu quả với chúng. Chủ yếu sẽ tập trung vào bốn kiểu dữ liệu:
INTEGERđể làm việc với số nguyên.TEXTđể xử lý chuỗi.BOOLEANđể làm việc với giá trị logic.RECORDđể xử lý cấu trúc dữ liệu động.
Mỗi kiểu dữ liệu tụi mình sẽ xem qua ví dụ thực tế để bạn thấy cách dùng nó như nào nhé.
Các kiểu dữ liệu được hỗ trợ trong PL/pgSQL
PL/pgSQL hỗ trợ tất cả các kiểu dữ liệu mà bạn đã biết trong PostgreSQL. Từ kiểu số đơn giản (INTEGER, NUMERIC) đến phức tạp hơn như array và JSONB. Cùng điểm qua mấy cái chính nha.
Kiểu nguyên thủy:
INTEGER,BIGINT,FLOAT,NUMERIC— kiểu số.TEXT,CHAR,VARCHAR— kiểu chuỗi.BOOLEAN— kiểu logic.
Kiểu phức tạp:
RECORD— để làm việc với tập dữ liệu động.ROWTYPE— để làm việc với kiểu dòng của bảng.- Array và JSON — sẽ học sau trong khóa này.
Làm việc với kiểu INTEGER
INTEGER là một trong những kiểu dữ liệu phổ biến nhất. Nó dùng để lưu số nguyên. Trong PL/pgSQL bạn có thể dùng kiểu này để tính toán, làm việc với id bản ghi và kiểm tra điều kiện.
Ví dụ: đếm số lượng bản ghi
Giả sử tụi mình có bảng students và muốn biết có bao nhiêu sinh viên trong database.
DO $$
DECLARE
total_students INTEGER; -- Biến để lưu số lượng sinh viên
BEGIN
SELECT COUNT(*) INTO total_students FROM students; -- Lưu kết quả truy vấn vào biến
RAISE NOTICE 'Số lượng sinh viên: %', total_students; -- In ra thông báo
END;
$$;
Lưu ý khi làm việc với INTEGER:
- Trong PL/pgSQL, gán giá trị cho biến dùng từ khóa
INTO. - Nếu bạn thử lưu giá trị thập phân vào
INTEGERsẽ bị lỗi. Trường hợp này dùngNUMERIChoặcFLOATnha.
Làm việc với kiểu TEXT
TEXT dùng để lưu dữ liệu dạng chuỗi. Rất tiện khi bạn cần làm việc với tên, mô tả hoặc bất kỳ text nào.
Ví dụ: in tên sinh viên
Ví dụ này tụi mình sẽ in ra tên tất cả sinh viên trong bảng students.
DO $$
DECLARE
student_name TEXT; -- Biến cho tên sinh viên
BEGIN
FOR student_name IN SELECT name FROM students LOOP
RAISE NOTICE 'Tên sinh viên: %', student_name; -- In từng tên
END LOOP;
END;
$$;
Một số hàm hữu ích khi làm việc với TEXT:
UPPER()vàLOWER()— chuyển sang chữ hoa/thường.CONCAT()— nối chuỗi.LENGTH()— độ dài chuỗi.
Ví dụ:
DO $$
DECLARE
full_name TEXT;
BEGIN
full_name := CONCAT('Alex', ' Min'); -- Nối chuỗi
RAISE NOTICE 'Tên đầy đủ: %', UPPER(full_name); -- In tên ở dạng chữ hoa
END;
$$;
Làm việc với kiểu BOOLEAN
BOOLEAN dùng để lưu giá trị logic: TRUE, FALSE và NULL. Kiểu này cực kỳ hữu ích khi kiểm tra điều kiện và lọc dữ liệu.
Ví dụ: kiểm tra sinh viên có hoạt động không
Giả sử bạn có bảng students với cột is_active cho biết sinh viên có đang hoạt động không.
DO $$
DECLARE
is_active BOOLEAN; -- Biến lưu trạng thái hoạt động
BEGIN
SELECT is_active INTO is_active FROM students WHERE id = 1; -- Lấy giá trị từ bảng
IF is_active THEN
RAISE NOTICE 'Sinh viên đang hoạt động!';
ELSE
RAISE NOTICE 'Sinh viên KHÔNG hoạt động.';
END IF;
END;
$$;
Lưu ý khi làm việc với BOOLEAN:
- Giá trị logic có thể dùng trực tiếp trong điều kiện
IFvàWHILE. - Giá trị
NULLtrong logic là "không xác định", nên nhớ kiểm tra kỹ khi dùng.
Làm việc với kiểu RECORD
RECORD là kiểu dữ liệu mạnh mẽ dùng để lưu dòng dữ liệu mà không cần biết trước cấu trúc. Rất tiện khi bạn làm việc với kết quả truy vấn SQL trả về nhiều cột.
Ví dụ: duyệt tất cả bản ghi trong bảng
Ví dụ sau tụi mình sẽ duyệt qua tất cả bản ghi trong bảng students và in ra tên cùng ID của từng sinh viên.
DO $$
DECLARE
student RECORD; -- Kiểu động để lưu dòng dữ liệu
BEGIN
FOR student IN SELECT id, name FROM students LOOP
RAISE NOTICE 'ID: %, Tên: %', student.id, student.name; -- Truy cập cột trong record
END LOOP;
END;
$$;
Lưu ý khi làm việc với RECORD:
- Biến kiểu
RECORDchỉ được gán giá trị trong vòng lặp hoặc khi dùng truy vấnSELECT INTO. - Truy cập cột bằng
record.tên_cột.
Kiểu dữ liệu ROWTYPE để làm việc với bảng
Nếu bạn muốn lưu cả một dòng từ bảng (và muốn kiểu dữ liệu rõ ràng), có thể dùng kiểu ROWTYPE. Nó tự động kế thừa cấu trúc dòng của bảng.
Ví dụ: làm việc với kiểu ROWTYPE
DO $$
DECLARE
student students%ROWTYPE; -- Biến có cấu trúc dòng của bảng students
BEGIN
SELECT * INTO student FROM students WHERE id = 1; -- Lấy dữ liệu dòng vào biến
RAISE NOTICE 'Tên sinh viên: %, Khóa học: %', student.name, student.course;
END;
$$;
Khác biệt giữa RECORD và ROWTYPE
| Đặc điểm | RECORD | ROWTYPE |
|---|---|---|
| Cấu trúc cột | Không xác định trước | Phụ thuộc vào bảng hoặc truy vấn |
| Cách dùng | Linh hoạt cho mọi kết quả | Gắn chặt với cấu trúc |
Ví dụ thực tế
Cùng viết function trả về số lượng sinh viên đang hoạt động và tên của họ nhé.
CREATE FUNCTION active_students_report() RETURNS TABLE(id INT, name TEXT) AS $$
BEGIN
RETURN QUERY
SELECT id, name FROM students WHERE is_active = TRUE;
END;
$$ LANGUAGE plpgsql;
Gọi function:
SELECT * FROM active_students_report();
Lỗi thường gặp khi làm việc với kiểu dữ liệu
Đôi khi làm việc với dữ liệu sẽ gặp lỗi. Đây là vài trường hợp phổ biến:
- Lỗi kiểu: thử gán chuỗi vào biến
INTEGER(ví dụ,my_var := 'abc';). - Dùng
NULLở chỗ cầnTRUEhoặcFALSE. - Dùng
RECORDmà chưa khởi tạo đúng cách.
Cách tránh lỗi:
- Luôn khai báo kiểu biến rõ ràng.
- Kiểm tra kiểu dữ liệu của cột trong bảng trước khi ghi dữ liệu.
- Dùng lệnh debug như
RAISE NOTICE.
Giờ thì bạn đã biết cách làm việc với các kiểu dữ liệu INTEGER, TEXT, BOOLEAN và RECORD trong PL/pgSQL rồi đó. Kiến thức này sẽ giúp bạn viết chương trình procedural cho PostgreSQL mạnh mẽ và phức tạp hơn nhiều!
GO TO FULL VERSION