Đị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ột và dữ 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ả
Schema
Chưa có bảng nào
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êngBả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 viewDROPVIEWIFEXISTS dept_headcount;CREATEVIEWdept_headcountASSELECTd.dept_name, COUNT(e.emp_id) AS headcountFROM department dLEFT JOIN employee e ONe.dept_id=d.dept_idGROUP BYd.dept_name;-- Sau khi định nghĩa, tham chiếu nó như bảngSELECT dept_name, headcount FROM dept_headcountORDER BY headcount DESC;-- Xóa khi xongDROPVIEW 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 employee và department 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ả
Schema
Chưa có bảng nào
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 viewTá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)DROPVIEWIFEXISTS emp_cohort;CREATEVIEWemp_cohortASSELECTname, hired_on,CASEWHEN hired_on <'2018-01-01'THEN'Veteran'WHEN hired_on <'2021-01-01'THEN'Mid'ELSE'Recent'ENDAS cohortFROM employee;SELECT cohort, COUNT(*) AS cntFROM emp_cohortGROUP BY cohortORDER BY cohort;DROPVIEW 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 khaiDROPVIEWIFEXISTS emp_public;CREATEVIEWemp_publicASSELECT emp_id, name, dept_id FROM employee;DROPVIEW 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ả
Schema
Chưa có bảng nào
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 JOIN và GROUP 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ọiKhi 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 banDROPVIEWIFEXISTS dept_sales;CREATEVIEWdept_salesASSELECTd.dept_name, SUM(s.amount) AS totalFROM sales sJOIN employee e ONs.emp_id=e.emp_idJOIN department d ONe.dept_id=d.dept_idGROUP BYd.dept_name;-- Người gọi chỉ cần SELECT từ view đã tổng hợpSELECT dept_name, total FROM dept_salesORDER BY total DESC;DROPVIEW 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 employee và sales 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 name và total 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ả
Schema
Chưa có bảng nào
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?