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,查询视图时可能会变慢,建议避免过度嵌套
相关推荐
懒羊羊不懒@1 天前
Java基础语法—最小单位、及注释
java·c语言·开发语言·数据结构·学习·算法
ss2731 天前
手写Spring第4弹: Spring框架进化论:15年技术变迁:从XML配置到响应式编程的演进之路
xml·java·开发语言·后端·spring
DokiDoki之父1 天前
MyBatis—增删查改操作
java·spring boot·mybatis
李白你好1 天前
一款专业的多数据库安全评估工具,支持 **PostgreSQL、MySQL、Redis、MSSQL** 等多种数据库的后渗透操作
数据库·mysql·postgresql
兩尛1 天前
Spring面试
java·spring·面试
Java中文社群1 天前
服务器被攻击!原因竟然是他?真没想到...
java·后端
恋红尘1 天前
Mysql
数据库·mysql
Full Stack Developme1 天前
java.nio 包详解
java·python·nio
paishishaba1 天前
数据库设计原则
数据库
零千叶1 天前
【面试】Java JVM 调优面试手册
java·开发语言·jvm