在 SQL 操作中,你是否遇到过 "频繁查询多表关联的固定结果""不想让他人看到表中的敏感字段" 这类问题?比如 "每周都要查'技术部员工的姓名、职位、薪资'",每次都写多表关联语句很麻烦;又比如 "给实习生开放数据查询权限,但不能让他们看到员工的身份证号、手机号"。这时候,视图(View) 就是解决这些问题的高效工具。今天我们用 "企业员工信息表" 和 "部门表" 为案例,从零学会视图的创建、使用与权限控制,代码可直接复制运行。
我整理了一些学习资料,包含专业、考试、课程等资料,还有游戏和软件的合集。
学习资料合集文档https://www.kdocs.cn/l/cjchDXwklk1B
一、先搞懂:什么是视图?
简单来说,视图就是 "一张虚拟的表"------ 它不是真实存储数据的表,而是由一个 SQL 查询语句(比如多表关联查询、字段筛选查询)定义的 "结果集"。我们可以像操作普通表一样查询视图,但视图的底层数据还是来自原表:
- 原表数据更新时,视图的查询结果也会同步更新;
- 视图本身不存储数据,只保存定义它的 SQL 语句。
核心价值:简化复杂查询、控制数据访问权限、保证数据一致性。
准备案例数据:员工表与部门表
为了体现视图的作用,我们创建两张关联表:"员工表(employee)" 和 "部门表(department)",包含敏感字段(如身份证号、手机号)和关联字段(部门 ID),代码可直接运行:
sql
-- 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),每次写关联语句很麻烦,所以创建一个视图来简化操作。
代码:
sql
-- 创建视图:员工-部门关联视图(简化多表查询)
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:创建 "隐藏敏感字段" 的视图
需求:给实习生开放数据查询权限,但不能让他们看到员工的身份证号、手机号,所以创建一个不含敏感字段的视图。
代码:
sql
-- 创建视图:员工信息公开视图(隐藏敏感字段)
CREATE VIEW emp_public_view AS
SELECT
emp_name AS 员工姓名,
position AS 职位,
salary AS 月薪,
hire_date AS 入职日期
FROM employee; -- 只包含非敏感字段
场景 3:创建 "筛选特定数据" 的视图
需求:经常需要查询 "技术部的员工信息",所以创建一个只包含技术部员工的视图。
代码:
sql
-- 创建视图:技术部员工视图(筛选特定部门数据)
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:查询 "员工 - 部门关联视图"
需求:查看所有员工的姓名、部门、职位、薪资。
代码:
sql
-- 查询视图:直接用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 年之后的员工。
代码:
sql
-- 查询视图时,还能加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 修改
需求:给 "员工 - 部门关联视图" 添加 "部门位置" 字段。
代码:
sql
-- 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 重建(推荐)
如果视图不存在,就创建;如果已存在,就覆盖修改,避免 "视图已存在" 的报错。
需求:修改 "技术部员工视图",增加 "部门位置" 字段。
代码:
sql
-- 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删除,不会影响原表数据(因为视图是虚拟表)。
代码:
sql
-- 删除"员工信息公开视图"
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. 创建数据库用户(给实习生创建用户)
sql
-- 创建用户:用户名=intern,密码=123456(仅本地访问,@'localhost'表示本地)
CREATE USER IF NOT EXISTS 'intern'@'localhost' IDENTIFIED BY '123456';
2. 给用户分配视图的查询权限(只能查,不能改)
需求:给实习生用户(intern)分配 "tech_dept_emp_view" 和 "emp_dept_view" 的查询权限(SELECT权限),但不能分配原表的权限,也不能分配修改视图的权限。
代码:
sql
-- 给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),也不能修改视图:
sql
-- 能查询授权的视图(正常返回结果)
SELECT * FROM tech_dept_emp_view;
-- 不能查询原表(会提示"拒绝访问")
SELECT * FROM employee;
-- 不能修改视图(会提示"没有权限")
ALTER VIEW tech_dept_emp_view AS SELECT * FROM employee;
4. 收回权限(如需取消授权)
如果实习生离职,用REVOKE收回权限:
sql
-- 收回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,查询视图时可能会变慢,建议避免过度嵌套