在 SQL 操作中,你是否遇到過 “頻繁查詢多表關聯的固定結果”“不想讓他人看到表中的敏感字段” 這類問題?比如 “每周都要查‘技術部員工的姓名、職位、薪資’”,每次都寫多表關聯語句很麻煩;又比如 “給實習生開放數據查詢權限,但不能讓他們看到員工的身份證號、手機號”。這時候,視圖(View) 就是解決這些問題的高效工具。今天我們用 “企業員工信息表” 和 “部門表” 為案例,從零學會視圖的創建、使用與權限控制,代碼可直接復制運行。
我整理了一些學習資料,包含專業、考試、課程等資料,還有游戲和軟件的合集。
學習資料合集文檔https://www.kdocs.cn/l/cjchDXwklk1B
一、先搞懂:什么是視圖?
簡單來說,視圖就是 “一張虛擬的表”—— 它不是真實存儲數據的表,而是由一個 SQL 查詢語句(比如多表關聯查詢、字段篩選查詢)定義的 “結果集”。我們可以像操作普通表一樣查詢視圖,但視圖的底層數據還是來自原表:
- 原表數據更新時,視圖的查詢結果也會同步更新;
- 視圖本身不存儲數據,只保存定義它的 SQL 語句。
核心價值:簡化復雜查詢、控制數據訪問權限、保證數據一致性。
準備案例數據:員工表與部門表
為了體現視圖的作用,我們創建兩張關聯表:“員工表(employee)” 和 “部門表(department)”,包含敏感字段(如身份證號、手機號)和關聯字段(部門 ID),代碼可直接運行:
-- 1. 創建部門表(存儲部門信息)
CREATE TABLE department (dept_id INT PRIMARY KEY, -- 部門ID(主鍵)dept_name VARCHAR(20) NOT NULL, -- 部門名稱(如技術部、銷售部)dept_location VARCHAR(30) NOT NULL -- 部門位置(如1號樓3層)
);-- 2. 創建員工表(存儲員工信息,關聯部門表)
CREATE TABLE employee (emp_id INT PRIMARY KEY AUTO_INCREMENT, -- 員工ID(自增主鍵)emp_name VARCHAR(20) NOT NULL, -- 員工姓名dept_id INT NOT NULL, -- 部門ID(關聯部門表)position VARCHAR(20) NOT NULL, -- 職位(如工程師、經理)salary DECIMAL(10,2) NOT NULL, -- 月薪id_card CHAR(18) NOT NULL, -- 身份證號(敏感字段)phone CHAR(11) NOT NULL, -- 手機號(敏感字段)hire_date DATE NOT NULL, -- 入職日期-- 外鍵約束:確保員工的部門ID在部門表中存在FOREIGN KEY (dept_id) REFERENCES department(dept_id)
);-- 3. 插入部門數據
INSERT INTO department (dept_id, dept_name, dept_location)
VALUES
(101, '技術部', '1號樓3層'),
(102, '銷售部', '1號樓5層'),
(103, '人事部', '2號樓2層');-- 4. 插入員工數據(包含3個部門的員工,含敏感字段)
INSERT INTO employee (emp_name, dept_id, position, salary, id_card, phone, hire_date)
VALUES
('張三', 101, '后端工程師', 15000.00, '110101199501011234', '13812345678', '2020-03-15'),
('李四', 101, '前端工程師', 14000.00, '110101199602022345', '13987654321', '2021-05-20'),
('王五', 102, '銷售經理', 18000.00, '110101199303033456', '13711112222', '2019-01-10'),
('趙六', 102, '銷售員', 12000.00, '110101199704044567', '13633334444', '2022-07-05'),
('孫七', 103, '人事專員', 10000.00, '110101199805055678', '13555556666', '2023-02-28'),
('周八', 103, '招聘主管', 13000.00, '110101199406066789', '13477778888', '2021-09-12');-- 查看原表數據(確認插入成功)
SELECT * FROM department;
SELECT * FROM employee LIMIT 3;
原表數據示例(員工表):
emp_id | emp_name | dept_id | position | salary | id_card | phone | hire_date |
1 | 張三 | 101 | 后端工程師 | 15000.00 | 110101199501011234 | 13812345678 | 2020-03-15 |
2 | 李四 | 101 | 前端工程師 | 14000.00 | 110101199602022345 | 13987654321 | 2021-05-20 |
3 | 王五 | 102 | 銷售經理 | 18000.00 | 110101199303033456 | 13711112222 | 2019-01-10 |
二、視圖的核心操作:創建、查詢、修改、刪除
視圖的操作語法簡單,核心圍繞 “創建視圖(CREATE VIEW)” 和 “使用視圖(SELECT)”,我們逐個講解。
1. 創建視圖(CREATE VIEW):核心語法
語法:
CREATE VIEW 視圖名 AS 定義視圖的SQL查詢語句;
場景 1:創建 “簡化多表關聯” 的視圖
需求:頻繁需要 “查詢員工姓名、部門名稱、職位、薪資、入職日期”,這個需求需要關聯員工表和部門表(employee JOIN department),每次寫關聯語句很麻煩,所以創建一個視圖來簡化操作。
代碼:
-- 創建視圖:員工-部門關聯視圖(簡化多表查詢)
CREATE VIEW emp_dept_view AS
SELECT e.emp_name AS 員工姓名,d.dept_name AS 部門名稱,e.position AS 職位,e.salary AS 月薪,e.hire_date AS 入職日期
FROM employee e
JOIN department d ON e.dept_id = d.dept_id; -- 多表關聯邏輯封裝在視圖中
場景 2:創建 “隱藏敏感字段” 的視圖
需求:給實習生開放數據查詢權限,但不能讓他們看到員工的身份證號、手機號,所以創建一個不含敏感字段的視圖。
代碼:
-- 創建視圖:員工信息公開視圖(隱藏敏感字段)
CREATE VIEW emp_public_view AS
SELECT emp_name AS 員工姓名,position AS 職位,salary AS 月薪,hire_date AS 入職日期
FROM employee; -- 只包含非敏感字段
場景 3:創建 “篩選特定數據” 的視圖
需求:經常需要查詢 “技術部的員工信息”,所以創建一個只包含技術部員工的視圖。
代碼:
-- 創建視圖:技術部員工視圖(篩選特定部門數據)
CREATE VIEW tech_dept_emp_view AS
SELECT e.emp_name AS 員工姓名,e.position AS 職位,e.salary AS 月薪,e.hire_date AS 入職日期
FROM employee e
JOIN department d ON e.dept_id = d.dept_id
WHERE d.dept_name = '技術部'; -- 篩選條件封裝在視圖中
2. 查詢視圖:像查普通表一樣簡單
創建視圖后,查詢視圖的語法和查詢普通表完全一致,不用再寫復雜的關聯或篩選邏輯。
例子 1:查詢 “員工 - 部門關聯視圖”
需求:查看所有員工的姓名、部門、職位、薪資。
代碼:
-- 查詢視圖:直接用SELECT查視圖,無需多表關聯
SELECT * FROM emp_dept_view;
運行結果:
員工姓名 | 部門名稱 | 職位 | 月薪 | 入職日期 |
張三 | 技術部 | 后端工程師 | 15000.00 | 2020-03-15 |
李四 | 技術部 | 前端工程師 | 14000.00 | 2021-05-20 |
王五 | 銷售部 | 銷售經理 | 18000.00 | 2019-01-10 |
趙六 | 銷售部 | 銷售員 | 12000.00 | 2022-07-05 |
孫七 | 人事部 | 人事專員 | 10000.00 | 2023-02-28 |
周八 | 人事部 | 招聘主管 | 13000.00 | 2021-09-12 |
例子 2:查詢 “技術部員工視圖” 并篩選
需求:查看技術部入職時間在 2021 年之后的員工。
代碼:
-- 查詢視圖時,還能加WHERE篩選條件
SELECT * FROM tech_dept_emp_view
WHERE hire_date >= '2021-01-01';
運行結果:
員工姓名 | 職位 | 月薪 | 入職日期 |
李四 | 前端工程師 | 14000.00 | 2021-05-20 |
3. 修改視圖:兩種方式(ALTER VIEW / CREATE OR REPLACE VIEW)
如果需要修改視圖的定義(比如添加字段、修改篩選條件),有兩種常用方式:
方式 1:用 ALTER VIEW 修改
需求:給 “員工 - 部門關聯視圖” 添加 “部門位置” 字段。
代碼:
-- ALTER VIEW修改視圖定義
ALTER VIEW emp_dept_view AS
SELECT e.emp_name AS 員工姓名,d.dept_name AS 部門名稱,d.dept_location AS 部門位置, -- 新增字段e.position AS 職位,e.salary AS 月薪,e.hire_date AS 入職日期
FROM employee e
JOIN department d ON e.dept_id = d.dept_id;-- 驗證修改結果
SELECT 員工姓名, 部門名稱, 部門位置 FROM emp_dept_view;
方式 2:用 CREATE OR REPLACE VIEW 重建(推薦)
如果視圖不存在,就創建;如果已存在,就覆蓋修改,避免 “視圖已存在” 的報錯。
需求:修改 “技術部員工視圖”,增加 “部門位置” 字段。
代碼:
-- CREATE OR REPLACE VIEW:存在則修改,不存在則創建
CREATE OR REPLACE VIEW tech_dept_emp_view AS
SELECT e.emp_name AS 員工姓名,d.dept_name AS 部門名稱,d.dept_location AS 部門位置, -- 新增字段e.position AS 職位,e.salary AS 月薪,e.hire_date AS 入職日期
FROM employee e
JOIN department d ON e.dept_id = d.dept_id
WHERE d.dept_name = '技術部';-- 驗證修改結果
SELECT * FROM tech_dept_emp_view;
4. 刪除視圖:DROP VIEW
如果視圖不再需要,用DROP VIEW刪除,不會影響原表數據(因為視圖是虛擬表)。
代碼:
-- 刪除“員工信息公開視圖”
DROP VIEW IF EXISTS emp_public_view; -- IF EXISTS:避免“視圖不存在”的報錯-- 驗證刪除結果(會提示“表不存在”,說明刪除成功)
SELECT * FROM emp_public_view;
三、視圖的核心作用:3 個實用價值
通過前面的案例,我們能直觀感受到視圖的作用,這里總結 3 個核心價值,幫你判斷什么時候該用視圖:
1. 簡化復雜查詢,提高效率
把多表關聯、復雜篩選的邏輯封裝在視圖中,后續查詢只需要SELECT * FROM 視圖名,不用重復寫長 SQL。比如前面的 “員工 - 部門關聯視圖”,把JOIN邏輯封裝后,每次查詢都能節省寫關聯語句的時間。
2. 控制數據權限,保護敏感信息
通過視圖隱藏原表中的敏感字段(如身份證號、手機號、薪資),給不同角色開放不同視圖的權限,實現 “數據隔離”。比如給實習生開放 “emp_public_view”(不含敏感字段),給部門經理開放 “emp_dept_view”(含部門信息),保證數據安全。
3. 保證數據查詢的一致性
如果多個場景需要用相同的查詢邏輯(比如 “查詢月薪大于 12000 的員工”),把這個邏輯封裝在視圖中,所有場景都查這個視圖,避免不同人寫的 SQL 邏輯不一致導致結果差異。比如創建 “high_salary_emp_view”(篩選月薪 > 12000 的員工),所有人都查這個視圖,確保結果統一。
四、視圖的權限控制:給不同角色分配權限
在實際工作中,視圖的權限控制通常和 “數據庫用戶” 結合 —— 創建不同的數據庫用戶,給他們分配不同視圖的查詢權限,實現 “按需授權”。這里以 MySQL 為例,講解基礎的權限分配操作。
1. 創建數據庫用戶(給實習生創建用戶)
-- 創建用戶:用戶名=intern,密碼=123456(僅本地訪問,@'localhost'表示本地)
CREATE USER IF NOT EXISTS 'intern'@'localhost' IDENTIFIED BY '123456';
2. 給用戶分配視圖的查詢權限(只能查,不能改)
需求:給實習生用戶(intern)分配 “tech_dept_emp_view” 和 “emp_dept_view” 的查詢權限(SELECT權限),但不能分配原表的權限,也不能分配修改視圖的權限。
代碼:
-- 給intern用戶分配兩個視圖的SELECT權限
GRANT SELECT ON student_management.tech_dept_emp_view TO 'intern'@'localhost';
GRANT SELECT ON student_management.emp_dept_view TO 'intern'@'localhost';-- 刷新權限,讓授權生效
FLUSH PRIVILEGES;
3. 驗證權限(切換到 intern 用戶)
用 intern 用戶登錄數據庫后,只能查詢被授權的視圖,不能查詢原表(如 employee、department),也不能修改視圖:
-- 能查詢授權的視圖(正常返回結果)
SELECT * FROM tech_dept_emp_view;-- 不能查詢原表(會提示“拒絕訪問”)
SELECT * FROM employee;-- 不能修改視圖(會提示“沒有權限”)
ALTER VIEW tech_dept_emp_view AS SELECT * FROM employee;
4. 收回權限(如需取消授權)
如果實習生離職,用REVOKE收回權限:
-- 收回intern用戶對tech_dept_emp_view的SELECT權限
REVOKE SELECT ON student_management.tech_dept_emp_view FROM 'intern'@'localhost';-- 刷新權限
FLUSH PRIVILEGES;
五、視圖的使用注意事項:3 個避坑點
- 視圖不能替代原表:視圖是基于原表的虛擬表,不能存儲數據,修改視圖的查詢結果(如UPDATE 視圖名 SET 字段=值)會同步修改原表數據(需謹慎!),建議盡量只用于查詢,不用于修改。
- 復雜視圖可能影響性能:如果視圖包含多層嵌套(視圖基于另一個視圖創建)、大量JOIN或GROUP BY,查詢視圖時可能會變慢,建議避免過度嵌套