SQL 进阶指南:视图的创建与使用(视图语法 / 作用 / 权限控制)

在 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 个避坑点

  1. 视图不能替代原表:视图是基于原表的虚拟表,不能存储数据,修改视图的查询结果(如UPDATE 视图名 SET 字段=值)会同步修改原表数据(需谨慎!),建议尽量只用于查询,不用于修改。
  1. 复杂视图可能影响性能:如果视图包含多层嵌套(视图基于另一个视图创建)、大量JOIN或GROUP BY,查询视图时可能会变慢,建议避免过度嵌套
相关推荐
杨杨杨大侠4 小时前
第1章:事件驱动框架基础概念
java·github·eventbus
程序员皮皮林4 小时前
Java jar 如何防止被反编译?代码写的太烂,害怕被人发现
java·开发语言·jar
neo_Ggx234 小时前
MySQL数据库备份攻略:从Docker到本地部署
数据库·mysql·docker
麦兜*4 小时前
MongoDB 性能调优:十大实战经验总结 详细介绍
数据库·spring boot·mongodb·spring cloud·缓存·硬件架构
盒马coding5 小时前
PostgreSQL与Greenplum数据库的编程语言连接
数据库·postgresql
橙序员小站5 小时前
搞定系统面试题:如何实现分布式Session管理
java·后端·面试
叫我阿柒啊5 小时前
从Java全栈到Vue3实战:一次真实面试中的技术探索
java·数据库·spring boot·微服务·typescript·vue3·restful
代码的余温5 小时前
SQL Server全链路安全防护
数据库·安全·sqlserver
武子康5 小时前
Java-118 深入浅出 MySQL ShardingSphere 分片剖析:SQL 支持范围、限制与优化实践
java·大数据·数据库·分布式·sql·mysql·性能优化