MySQL 视图完全指南
本文档专门讲 视图(View):什么是视图、为什么用视图、怎么创建、查询、修改和删除,以及何时可更新、有哪些注意点。每一步都配有详细说明和大量示例,适合零基础新手跟着做。
目录
- 什么是视图
- 为什么使用视图
- 示例表与数据准备
- 创建视图
- 使用视图(像表一样查询)
- 修改视图
- 删除视图
- 视图的更新性(通过视图改数据)
- WITH CHECK OPTION(可选)
- 查看视图信息
- 常见错误与注意点
- 综合示例与速查表
1. 什么是视图
1.1 定义
视图是一张虚拟表。
它本身不存数据,而是保存一条 SELECT 语句;当你对视图做查询时,MySQL 会执行这条 SELECT,把结果临时当成一张表给你看。
可以理解为:
- 表:真正存数据的“实体表”。
- 视图:给某条查询结果起个名字,以后查这个“名字”就相当于重复执行那条查询,看起来像一张表。
1.2 通俗比喻
- 表 = 真实的成绩单原件。
- 视图 = 一张“只显示姓名和语文成绩”的名单,每次看这份名单时,都是根据原件现场筛选出来的,名单本身没有单独再存一份数据。
1.3 特点小结
- 不存数据(一般情况):数据仍在基表里,视图只是“查询的封装”。
- 像表一样用:可以 *SELECT FROM 视图名**,也可以和别的表/视图 JOIN。
- 随基表变化:基表数据变了,查视图的结果也会变。
- 可设置权限:可以对视图单独授权,限制用户只能看某些列或某些行。
2. 为什么使用视图
2.1 简化复杂查询
一条很长的 SELECT(多表 JOIN、子查询、一堆条件)写一次,保存成视图,以后只要 *SELECT FROM 视图名** 即可,不用反复写长 SQL。
2.2 隐藏部分列或行
只把“允许别人看的列”做到视图里,基表里其他列(如密码、手机号)不放进视图,查视图的人就看不到。
2.3 统一业务含义
例如“在售商品”= 状态为上架且库存>0,可以做成视图 v_products_on_sale,大家查在售商品都查这个视图,逻辑一致。
2.4 便于权限控制
对视图授权,而不是直接对多张基表授权,管理更清晰。
3. 示例表与数据准备
后面示例基于下面两张表,请先建好并插入数据。
3.1 学生表 students
CREATE TABLE IF NOT EXISTS students (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
gender CHAR(1) DEFAULT '男',
age INT,
class_name VARCHAR(20)
);
INSERT INTO students (name, gender, age, class_name) VALUES
('张三', '男', 18, '高一1班'),
('李四', '女', 17, '高一2班'),
('王五', '男', 18, '高一1班'),
('赵六', '女', 17, '高一2班'),
('钱七', '男', 19, '高一1班');
3.2 成绩表 scores
CREATE TABLE IF NOT EXISTS scores (
id INT PRIMARY KEY AUTO_INCREMENT,
student_id INT NOT NULL,
subject VARCHAR(20) NOT NULL,
score DECIMAL(5,2)
);
INSERT INTO scores (student_id, subject, score) VALUES
(1, '语文', 85),
(1, '数学', 92),
(2, '语文', 88),
(2, '数学', 76),
(3, '语文', 72),
(3, '数学', 85);
4. 创建视图
4.1 基本语法
CREATE VIEW 视图名 [(列名1, 列名2, ...)]
AS
SELECT 列...
FROM 表名
[WHERE ...] [GROUP BY ...] [ORDER BY ...];
- 视图名:自己取,建议见名知意,如 v_student_list、v_score_summary。有的规范会加前缀 v_ 表示视图。
- AS 后面是一条完整的 SELECT;视图的“内容”就是这条查询的结果。
- 可选 [(列名1, 列名2, …)]:给视图的列起名;不写则用 SELECT 里的列名或别名。
4.2 示例:只包含姓名和班级的视图
CREATE VIEW v_student_basic AS
SELECT id, name, class_name
FROM students;
之后可以 *SELECT FROM v_student_basic;**,相当于只查 id、name、class_name,看不到 gender、age。
4.3 示例:带别名的视图(在 SELECT 里起别名)
CREATE VIEW v_student_list AS
SELECT id AS 学号, name AS 姓名, class_name AS 班级
FROM students;
查询视图时列名就是“学号、姓名、班级”。
也可以写在视图名后面:
CREATE VIEW v_student_list2 (学号, 姓名, 班级) AS
SELECT id, name, class_name FROM students;
4.4 示例:多表连接做成视图(学生 + 成绩)
“每个学生的每条成绩 + 姓名”可以做成视图,查起来像一张表:
CREATE VIEW v_student_score AS
SELECT s.id AS 学号, s.name AS 姓名, s.class_name AS 班级, sc.subject AS 科目, sc.score AS 分数
FROM students s
LEFT JOIN scores sc ON s.id = sc.student_id;
之后查 *SELECT FROM v_student_score;** 就能看到学生和成绩连在一起的结果。
4.5 示例:带条件的视图(只显示高一1班)
CREATE VIEW v_class1_students AS
SELECT id, name, gender, age
FROM students
WHERE class_name = '高一1班';
查这个视图只能看到高一1班的学生,相当于“固定了 WHERE 条件”。
4.6 示例:带聚合的视图(每个学生的总分)
CREATE VIEW v_student_total_score AS
SELECT s.id AS 学号, s.name AS 姓名, SUM(sc.score) AS 总分
FROM students s
LEFT JOIN scores sc ON s.id = sc.student_id
GROUP BY s.id, s.name;
这种带 GROUP BY、聚合函数 的视图一般不能通过视图做 INSERT/UPDATE/DELETE(见后文“视图的更新性”)。
4.7 若视图已存在:CREATE OR REPLACE VIEW
想“有则覆盖、无则创建”,可以用:
CREATE OR REPLACE VIEW v_student_basic AS
SELECT id, name, age, class_name
FROM students;
这样不会报“视图已存在”的错误,而是用新定义替换旧定义。
5. 使用视图(像表一样查询)
5.1 把视图当表用
视图建好后,可以像普通表一样参与 SELECT:
SELECT * FROM v_student_basic;
SELECT * FROM v_student_basic WHERE class_name = '高一1班';
SELECT 姓名, 分数 FROM v_student_score WHERE 分数 >= 85;
5.2 对视图再加条件、排序
SELECT * FROM v_student_score WHERE 分数 >= 80 ORDER BY 分数 DESC;
相当于在视图的查询结果上再筛、再排。
5.3 视图和表、视图和视图一起查
视图可以和表、其他视图一起 JOIN 或做子查询,例如(仅演示写法):
SELECT * FROM v_student_basic b
JOIN scores sc ON b.id = sc.student_id
WHERE sc.subject = '语文';
6. 修改视图
6.1 用 CREATE OR REPLACE VIEW(推荐)
直接重写视图定义,覆盖原来的:
CREATE OR REPLACE VIEW v_student_basic AS
SELECT id, name, age, class_name, gender
FROM students;
原来若没有 gender,现在视图里就多了 gender 一列。
6.2 用 ALTER VIEW(改选项,不改 SELECT)
ALTER VIEW 主要用于改视图的属性(如检查选项、算法、权限),一般不改 SELECT 内容;改内容用 CREATE OR REPLACE VIEW 更简单。
示例(改视图的 DEFINER 等,了解即可):
ALTER VIEW v_student_basic SQL SECURITY INVOKER;
7. 删除视图
7.1 语法
DROP VIEW 视图名;
示例:
DROP VIEW v_student_basic;
删除视图不会删除基表,也不会删数据,只是删掉“这个名字对应的那条 SELECT 封装”。
7.2 若不存在则忽略
DROP VIEW IF EXISTS v_student_basic;
适合写在脚本里,避免“视图不存在”报错。
7.3 一次删多个视图
DROP VIEW IF EXISTS v_student_basic, v_student_list, v_class1_students;
8. 视图的更新性(通过视图改数据)
8.1 什么时候可以通过视图 INSERT/UPDATE/DELETE
不是所有视图都能做 INSERT、UPDATE、DELETE。能做的视图通常要满足(简化说):
- 视图来自单张基表(或可更新连接视图,MySQL 有规则)。
- 没有 DISTINCT、GROUP BY、HAVING、聚合函数、子查询 等导致“一行不对应基表一行”的情况。
- 没有 UNION。
- 视图中包含的列都对应到基表的可更新列(如包含主键便于定位行)。
具体以 MySQL 文档为准,这里只做概念和示例。
8.2 可更新视图示例
v_student_basic 若只是 SELECT id, name, class_name FROM students,且来自单表 students,一般可以通过视图更新基表:
UPDATE v_student_basic SET class_name = '高一2班' WHERE id = 1;
会真正更新 students 表里 id=1 的 class_name。
通过视图插入(若视图包含基表必填列且无默认的列,插入可能受限制):
INSERT INTO v_student_basic (name, class_name) VALUES ('新学生', '高一1班');
若 students 表里还有 NOT NULL 的列(如 gender)没在视图里,插入可能报错,因为基表需要这些列。
通过视图删除:
DELETE FROM v_student_basic WHERE id = 5;
会删除 students 里 id=5 的行。
8.3 不可更新视图示例
- 带 GROUP BY、SUM、AVG 的视图(如 v_student_total_score):一行对应多行聚合结果,无法唯一对应回基表的一行,一般不能通过该视图 INSERT/UPDATE/DELETE。
- 多表 JOIN 的视图:MySQL 对多表可更新视图有规则,很多情况下不允许更新,或只允许更新其中一张基表。
建议:若要通过视图改数据,尽量用单表、无聚合、无 GROUP BY 的简单视图,并先小范围测试。
8.4 小结
- 视图主要用来查,改数据要谨慎。
- 简单单表视图可能可更新;带聚合、多表复杂视图多数只读。
9. WITH CHECK OPTION(可选)
9.1 作用
在可更新视图上,WITH CHECK OPTION 表示:通过视图 INSERT 或 UPDATE 时,新行必须仍然满足视图的 WHERE 条件,否则拒绝操作。
例如视图只包含 class_name = ‘高一1班’,若加上 WITH CHECK OPTION,你通过视图把某人的 class_name 改成 ‘高一2班’,改完后该行就不在视图条件内了,会被拒绝。
9.2 语法
CREATE VIEW v_class1 AS
SELECT id, name, class_name FROM students WHERE class_name = '高一1班'
WITH CHECK OPTION;
之后:
UPDATE v_class1 SET class_name = '高一2班' WHERE id = 1;
会报错(或拒绝),因为更新后 id=1 不再满足 class_name=’高一1班’。
9.3 CASCADED 与 LOCAL(了解)
WITH CASCADED CHECK OPTION:严格按本视图条件检查(并级联底层视图条件)。
WITH LOCAL CHECK OPTION:只检查本视图定义的条件。
新手知道有“检查选项”即可,需要时再查文档。
10. 查看视图信息
10.1 查看当前库有哪些视图
视图也在“表”的名单里,用 SHOW TABLES 可以看到;或查系统库:
SHOW FULL TABLES WHERE Table_type = 'VIEW';
10.2 查看视图定义(建表/建视图语句)
SHOW CREATE VIEW 视图名;
会显示创建该视图的完整 SQL,包括 SELECT 语句。
10.3 查看视图结构(列名、类型等)
把视图当表看,用 DESC:
DESC v_student_basic;
11. 常见错误与注意点
11.1 视图名已存在
若不加 OR REPLACE,同名视图已存在会报错。可改用 CREATE OR REPLACE VIEW 或先 DROP VIEW 再 CREATE VIEW。
11.2 视图依赖的基表或列被删、被改
若基表被删除或列被删改,视图再查会报错。修改表结构后,若视图用到了被改的列,需要 CREATE OR REPLACE VIEW 更新视图定义。
11.3 在视图中用了 ORDER BY
视图中可以写 ORDER BY,但“视图”本身是无序的,查视图时再 ORDER BY 才保证顺序;有些数据库对视图里的 ORDER BY 有规定,MySQL 允许但不必依赖视图内 ORDER BY 作为最终顺序,建议在查询视图时再排序。
11.4 视图不能建索引
视图是虚拟表,不能在视图上建索引;索引只能建在基表上。视图的查询速度取决于基表索引和视图的 SELECT 复杂度。
11.5 嵌套过深
视图可以基于另一个视图(A 视图的 SELECT 来自 B 视图),但层级太多会难维护、难优化,一般一两层即可。
12. 综合示例与速查表
12.1 综合示例(可整段执行)
USE school;
-- 1. 简单单表视图
CREATE OR REPLACE VIEW v_student_basic AS
SELECT id, name, class_name FROM students;
-- 2. 带别名的视图
CREATE OR REPLACE VIEW v_student_list (学号, 姓名, 班级) AS
SELECT id, name, class_name FROM students;
-- 3. 带条件的视图
CREATE OR REPLACE VIEW v_class1_students AS
SELECT id, name, age FROM students WHERE class_name = '高一1班';
-- 4. 多表连接视图
CREATE OR REPLACE VIEW v_student_score AS
SELECT s.id AS 学号, s.name AS 姓名, sc.subject AS 科目, sc.score AS 分数
FROM students s LEFT JOIN scores sc ON s.id = sc.student_id;
-- 5. 带聚合的视图(一般只读)
CREATE OR REPLACE VIEW v_student_total AS
SELECT s.id AS 学号, s.name AS 姓名, SUM(sc.score) AS 总分
FROM students s LEFT JOIN scores sc ON s.id = sc.student_id
GROUP BY s.id, s.name;
-- 使用视图
SELECT * FROM v_student_basic;
SELECT * FROM v_student_score WHERE 分数 >= 85;
SELECT * FROM v_student_total ORDER BY 总分 DESC;
-- 查看视图定义
SHOW CREATE VIEW v_student_basic;
-- 删除视图(演示用,可选)
-- DROP VIEW IF EXISTS v_student_basic, v_student_list, v_class1_students, v_student_score, v_student_total;
12.2 视图速查表
| 操作 | 命令 / 写法 |
|---|---|
| 创建视图 | CREATE VIEW 视图名 AS SELECT ...; |
| 创建或替换 | CREATE OR REPLACE VIEW 视图名 AS SELECT ...; |
| 查视图 | SELECT * FROM 视图名 [WHERE ...]; |
| 查看定义 | SHOW CREATE VIEW 视图名; |
| 查看结构 | DESC 视图名; |
| 删除视图 | DROP VIEW 视图名; 或 DROP VIEW IF EXISTS 视图名; |
| 检查选项 | 在 CREATE VIEW 末尾加 WITH CHECK OPTION |
注意:视图不存数据,只存 SELECT;基表变了,查视图结果就变;带聚合/多表复杂视图一般只读,简单单表视图可能可更新。
把“创建视图、当表查、修改与删除、可更新性、WITH CHECK OPTION”过一遍后,你就能用视图简化常用查询、隐藏部分列或行。建议在本地按上面的示例建好几类视图(单表、多表、带聚合),再 SELECT、SHOW CREATE VIEW、DESC 多试几次,巩固视图的用法。