Đôi khi truy vấn SQL của bạn dài quá trời, phức tạp và lặp đi lặp lại. Ví dụ, bạn làm báo cáo cho sinh viên với điểm trung bình và số lượng khoá học — và bạn phải viết cùng một subquery ở 5 chỗ khác nhau. Để khỏi copy-paste hoài, hãy dùng view — hay VIEW.
VIEW giống như “truy vấn đã lưu”, bạn đặt tên cho nó và dùng như một bảng bình thường. Nó không lưu dữ liệu, chỉ lưu cấu trúc truy vấn thôi.
Cái này đặc biệt hữu ích khi bạn muốn:
- làm cho SQL dễ đọc hơn;
- tái sử dụng truy vấn phức tạp;
- giấu mấy chi tiết kỹ thuật khỏi user;
- phân quyền truy cập (chỉ show dữ liệu cần thiết).
VIEW hoạt động như thế nào?
Tạo view nghĩa là tạo một bảng giả dựa trên truy vấn SELECT. Ví dụ:
CREATE VIEW student_avg_grades AS
SELECT
s.student_id,
s.name,
AVG(g.grade) AS avg_grade
FROM
students s
JOIN
grades g ON s.student_id = g.student_id
GROUP BY
s.student_id, s.name;
Bây giờ bạn có thể truy vấn student_avg_grades như một bảng bình thường:
SELECT * FROM student_avg_grades WHERE avg_grade > 4.5;
Ví dụ ở trường đại học
Bạn thường xuyên phân tích sinh viên, khoá học và điểm số của họ. Giả sử bạn cần tạo báo cáo tổng hợp cho từng sinh viên:
- tên,
- số lượng đăng ký khoá học,
- điểm trung bình.
Nếu làm một phát trong một truy vấn — sẽ rất dài và khó đọc. Dễ hơn nhiều nếu chia nhỏ: đầu tiên tạo hai view (VIEW), rồi kết hợp lại.
Bảng students
| id | name |
|---|---|
| 1 | Alex Lin |
| 2 | Anna Song |
| 3 | Maria Chi |
| 4 | Dan Seth |
Bảng enrollments
| student_id | course_id | grade |
|---|---|---|
| 1 | 1 | 90 |
| 1 | 2 | 85 |
| 2 | 2 | 88 |
| 2 | 3 | 91 |
| 3 | 1 | 75 |
| 3 | 3 | NULL |
- View: số lượng khoá học
View này đếm số khoá học của mỗi sinh viên:
CREATE VIEW student_course_count AS
SELECT
student_id,
COUNT(*) AS course_count
FROM
enrollments
GROUP BY student_id;
Kết quả:
| name |
|---|
| Alex Lin |
| Anna Song |
| Maria Chi |
- View: điểm trung bình. Cái này là điểm trung bình của sinh viên (nếu không có điểm thì là NULL, và không ảnh hưởng):
CREATE VIEW student_avg_grade AS
SELECT
student_id,
AVG(grade) AS avg_grade
FROM
enrollments
WHERE grade IS NOT NULL
GROUP BY student_id;
- Dùng mấy
VIEWnày
SELECT
s.name,
c.course_count,
a.avg_grade
FROM
students s
LEFT JOIN student_course_count c ON s.student_id = c.student_id
LEFT JOIN student_avg_grade a ON s.student_id = a.student_id;
Bây giờ bạn có truy vấn sạch sẽ, dễ hiểu. Quan trọng nhất — dễ bảo trì.
Khả năng cập nhật của VIEW
View thường không chứa dữ liệu — nó chỉ là "wrapper" cho truy vấn thôi. Tuy nhiên, bạn vẫn có thể dùng nó để cập nhật dữ liệu, nếu VIEW thoả mãn một số điều kiện (ví dụ: không có JOIN, GROUP BY, hàm tổng hợp và subquery).
Ví dụ view có thể cập nhật:
CREATE VIEW active_students AS
SELECT * FROM students WHERE active = true;
Bây giờ bạn có thể làm:
UPDATE active_students SET name = 'Ivan Petrov' WHERE student_id = 2;
Nhưng nếu VIEW phức tạp (ví dụ có JOIN hoặc GROUP BY), nó sẽ chỉ đọc được thôi. Muốn cập nhật thì phải dùng INSTEAD OF trigger, cái này nâng cao rồi nha.
Làm sao xoá hoặc sửa VIEW
Xoá:
DROP VIEW student_avg_grade;
Sửa:
CREATE OR REPLACE VIEW student_avg_grade AS
SELECT student_id, ROUND(AVG(grade), 2) AS avg_grade
FROM grades
GROUP BY student_id;
Ví dụ: khi nào VIEW cực kỳ hữu ích
- Làm báo cáo
Mỗi VIEW — một logic riêng. Bạn có thể tạo report_enrollments_by_month, report_payments_by_year v.v.
- Phân quyền truy cập
Tạo VIEW chỉ show dữ liệu giới hạn (ví dụ không có thông tin cá nhân) và chỉ cấp quyền truy cập cho view đó.
- Tái sử dụng
Thay vì copy subquery — đặt tên cho nó thành VIEW.
Tips
- Đặt tên dễ hiểu:
view_avg_scores_by_group,active_users_view— đọc phát hiểu liền. - Đừng lồng
VIEWtrongVIEWtrongVIEW— dễ rối và khó debug lắm. - Chú ý hiệu năng: PostgreSQL sẽ tính lại
VIEWmỗi lần truy vấn, trừ khi bạn dùngMATERIALIZED VIEW.
VIEW là một trong những công cụ đơn giản và tiện nhất trong PostgreSQL. Không cần học gì mới, chỉ cần nghĩ khác đi: “Hay là lưu truy vấn này lại rồi dùng như bảng nhỉ?” Nếu truy vấn của bạn dài quá — gần như chắc chắn nó xứng đáng thành VIEW đó.
GO TO FULL VERSION