Học bằng cách đọc theo thứ tự

View (VIEW) — Định nghĩa và trường hợp sử dụng

Định nghĩa emp_dept (nhân viên kết hợp với phòng ban), emp_tier (band lương), và emp_sales (tổng theo nhân viên) bằng CREATE VIEW, rồi xem ba trường hợp sử dụng — tái sử dụng, phân quyền, trừu tượng hóa — và xem view tính lại ngay khi bảng nền thay đổi.

Dữ liệu dùng trong bài — employee / department / sales

Một view (VIEW) là một câu lệnh SELECT được đặt tên và lưu lại mà bạn có thể tham chiếu như một bảng.

Khác với một bảng, view không giữ dữ liệu của riêng nó — mỗi lần bạn tham chiếu nó, câu SELECT đã lưu chạy lại.

Trước khi vào bài tập, hãy xem định nghĩa cộtdữ liệu mẫu cho ba bảng dùng trong bài — employee / department / sales.

① Chạy PRAGMA table_info(employee); / PRAGMA table_info(department); / PRAGMA table_info(sales); để kiểm tra định nghĩa cột cho cả ba bảng.

② Chạy SELECT * FROM employee LIMIT 5; / SELECT * FROM department LIMIT 5; / SELECT * FROM sales LIMIT 5; để xem trước năm dòng đầu của mỗi bảng.

SQL Editor

Chạy truy vấn để xem kết quả

CREATE VIEW — Đặt tên cho một truy vấn phức tạp

Định nghĩa một view bằng CREATE VIEW tên_view AS SELECT ...;.

Một khi nó được định nghĩa, viết SELECT * FROM tên_view sẽ chạy SELECT đã lưu và trả về kết quả.

Vì view là một truy vấn đã lưu không có dữ liệu riêng, bất kỳ cập nhật nào lên các bảng nền sẽ xuất hiện ở lần tham chiếu view kế tiếp.

Khi không cần nữa, xóa nó bằng DROP VIEW tên_view;.

Nếu bạn muốn tạo lại view với cùng tên, chạy DROP VIEW IF EXISTS tên_view; trước CREATE VIEW để script có thể chạy lại được.

View là một SELECT đã lưu — không có dòng riêng
Bảngemployee / departmentCREATE VIEW v AS SELECT ... JOIN ...View v(không giữ dòng)SELECT * FROM vChạy SELECT đã lưumỗi lần tham chiếuKết quả mới nhất
Bảng giữ dữ liệu dòng, nhưng view chỉ lưu câu SELECT. Mỗi lần tham chiếu view sẽ chạy SELECT đã lưu đó trên các bảng nền.
-- Đặt tên cho truy vấn đếm nhân viên theo phòng ban dưới dạng view
DROP VIEW IF EXISTS dept_headcount;
CREATE VIEW dept_headcount AS
SELECT d.dept_name, COUNT(e.emp_id) AS headcount
FROM department d
LEFT JOIN employee e ON e.dept_id = d.dept_id
GROUP BY d.dept_name;

-- Sau khi định nghĩa, tham chiếu nó như bảng
SELECT dept_name, headcount FROM dept_headcount
ORDER BY headcount DESC;

-- Xóa khi xong
DROP VIEW dept_headcount;

Hãy tưởng tượng yêu cầu: "Tôi muốn xem danh sách nhân viên với tên phòng ban và địa điểm bên cạnh mỗi dòng, mà không cần viết JOIN mỗi lần." Trong một lần chạy, đưa view từ định nghĩa đến tham chiếu rồi xóa dưới dạng một script tự đứng vững. (Khi nó chạy đúng, phần giải thích sẽ hiện ra.)

① Định nghĩa một view tên emp_dept LEFT JOIN employeedepartment trên dept_id và trả về emp_id, name, salary, dept_name, và location. Đặt câu lệnh xóa view cùng tên nếu đã tồn tại trước định nghĩa, để script không bao giờ thất bại khi chạy lại.

② Lấy name, dept_name, và salary từ view và hiển thị 5 dòng đầu sắp xếp theo salary giảm dần.

③ Cuối cùng, xóa view để định nghĩa của nó không lưu lại trên trang.

SQL Editor

Chạy truy vấn để xem kết quả

Ba trường hợp sử dụng — tái sử dụng, phân quyền, trừu tượng hóa

Có ba lý do chính để dùng view.

Tái sử dụng: gói gọn một JOIN hoặc tổng hợp thường dùng dưới một tên để không phải viết lại cùng truy vấn nhiều lần.

Phân quyền: tạo một view chỉ phơi bày một tập con các cột hoặc dòng, và cấp quyền truy cập view thay vì bảng nền (ẩn các cột lương cao, chỉ hiện các dòng từ phòng ban của người dùng, v.v.).

Trừu tượng hóa: người gọi không cần biết cấu trúc nội bộ của view (nó kết hợp bảng nào, như thế nào) — biết tên view và các cột nó trả về là đủ.

Ba trường hợp sử dụng cho view
Trường hợpLợi íchTái sử dụngĐặt tên JOIN/agg thường dùngHết phải viết lạicùng một truy vấnPhân quyềnChỉ phơi bày cột/dòng lọcẨn cột/dòng nhạy cảmcho kiểm soát truy cậpTrừu tượng hóaẨn JOIN và biểu thức nội bộNgười gọi chỉ cầntên view và cột
Tái sử dụng, phân quyền, và trừu tượng hóa là ba lý do kinh điển để dùng view. Cả ba đều chia sẻ cùng ý tưởng: ẩn đi sự phức tạp hoặc các bảng nền khỏi người gọi.
-- (1) Trừu tượng hóa: view gắn nhãn nhân viên theo cohort năm tuyển dụng (người gọi không thấy biểu thức)
DROP VIEW IF EXISTS emp_cohort;
CREATE VIEW emp_cohort AS
SELECT name, hired_on,
  CASE
    WHEN hired_on < '2018-01-01' THEN 'Veteran'
    WHEN hired_on < '2021-01-01' THEN 'Mid'
    ELSE 'Recent'
  END AS cohort
FROM employee;

SELECT cohort, COUNT(*) AS cnt
FROM emp_cohort
GROUP BY cohort
ORDER BY cohort;

DROP VIEW emp_cohort;

-- (2) Phân quyền: view loại trừ lương và chỉ phơi bày các cột có thể công khai
DROP VIEW IF EXISTS emp_public;
CREATE VIEW emp_public AS
SELECT emp_id, name, dept_id FROM employee;
DROP VIEW emp_public;

Hãy tưởng tượng yêu cầu này: "Tôi muốn gói logic phân loại nhân viên thành các band lương (High / Mid / Low) ở một chỗ, và xác nhận rằng cập nhật bảng nền employee làm cho kết quả tổng hợp của view cập nhật tự động." Vì view là một SELECT đã lưu không có dữ liệu riêng, nó tính lại bảng nền mỗi lần bạn tham chiếu nó.

① Xóa view cùng tên nếu tồn tại, rồi định nghĩa view emp_tier với cột tier trả về High khi salary là 6.500.000 hoặc hơn, Mid khi nó từ 5.000.000 đến 6.500.000, và Low khi thấp hơn.

② Tổng hợp số người theo tier với bí danh cnt, và kiểm tra số đếm trước cập nhật.

③ INSERT một nhân viên mới vào employee (emp_id 999 / name 'Zoe' / dept_id 1 / manager_id NULL / city 'Tokyo' / salary 8000000 / hired_on '2024-01-01'), người sẽ rơi vào band High.

④ Chạy cùng truy vấn tổng hợp như ②, và xác nhận số High tăng lên 1 (bằng chứng cập nhật bảng nền hiện ngay qua view).

⑤ Dọn dẹp bằng cách DELETE dòng có emp_id = 999 và DROP view.

SQL Editor

Chạy truy vấn để xem kết quả

View tổng hợp rút gọn truy vấn phía người gọi

View có thể lưu các tổng hợp GROUP BY, không chỉ JOIN.

Nếu bạn gói một tổng hợp thường dùng — như tổng doanh số theo nhân viên — vào một view duy nhất, người gọi có thể bỏ qua JOINGROUP BY và đơn giản SELECT các dòng đã được tổng hợp.

Ví dụ bên dưới tổng hợp sales theo nhân viên, kết hợp với employee để gắn tên nhân viên, và định nghĩa cái đó là một view.

Người gọi chỉ cần tham chiếu view để thấy "ai bán bao nhiêu" — họ không phải nghĩ đến kết hợp và tổng hợp nội bộ.

View tổng hợp rút gọn truy vấn phía người gọi
Tổng hợp salesGROUP BY emp_idJOIN employee đểgắn tênView emp_sales(các dòng đã tổng hợp)SELECT name, totalFROM emp_salesNgười gọi bỏ qua JOINvà GROUP BY
Khi bạn gấp JOIN và GROUP BY vào view, người gọi nhận được kết quả tổng hợp chỉ bằng cách chạy một SELECT trên view.
-- Một view gắn tổng doanh số theo phòng ban với tên phòng ban
DROP VIEW IF EXISTS dept_sales;
CREATE VIEW dept_sales AS
SELECT d.dept_name, SUM(s.amount) AS total
FROM sales s
JOIN employee e   ON s.emp_id = e.emp_id
JOIN department d ON e.dept_id = d.dept_id
GROUP BY d.dept_name;

-- Người gọi chỉ cần SELECT từ view đã tổng hợp
SELECT dept_name, total FROM dept_sales
ORDER BY total DESC;

DROP VIEW dept_sales;

Hãy tưởng tượng yêu cầu: "Cho dashboard hiệu suất bán hàng, tôi muốn hiển thị các nhân viên hàng đầu theo tổng doanh số mà không viết JOIN và tổng hợp mỗi lần." Đưa view từ định nghĩa qua tham chiếu đến xóa dưới dạng script tự đứng vững trong một lần chạy.

① Kết hợp employeesales trên emp_id, tổng hợp tổng doanh số theo nhân viên với bí danh total, và định nghĩa kết quả là một view tên emp_sales. Các cột của view phải là emp_id, name, và total — tổng cộng ba cột. Đặt câu lệnh xóa-nếu-tồn-tại cho cùng tên view trước định nghĩa.

② Lấy nametotal từ view và hiển thị 5 dòng đầu sắp xếp theo total giảm dần, rồi theo name tăng dần làm tiêu chí phá hòa.

③ Cuối cùng, xóa view.

SQL Editor

Chạy truy vấn để xem kết quả
QUIZ

Kiểm tra kiến thức

Hãy trả lời từng câu hỏi một.

Câu 1Phát biểu nào mô tả đúng một view (VIEW)?

Câu 2Điều nào sau đây KHÔNG được liệt kê trong bài như một trường hợp sử dụng cho view?

Câu 3Sau khi định nghĩa view emp_tier, bạn INSERT một dòng mới vào bảng nền employee. Điều gì xảy ra khi bạn chạy SELECT * FROM emp_tier mà không định nghĩa lại view?