mysql数据库的视图

MySQL 视图完全指南

本文档专门讲 视图(View):什么是视图、为什么用视图、怎么创建、查询、修改和删除,以及何时可更新、有哪些注意点。每一步都配有详细说明和大量示例,适合零基础新手跟着做。


目录

  1. 什么是视图
  2. 为什么使用视图
  3. 示例表与数据准备
  4. 创建视图
  5. 使用视图(像表一样查询)
  6. 修改视图
  7. 删除视图
  8. 视图的更新性(通过视图改数据)
  9. WITH CHECK OPTION(可选)
  10. 查看视图信息
  11. 常见错误与注意点
  12. 综合示例与速查表

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_listv_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 有规则)。
  • 没有 DISTINCTGROUP BYHAVING聚合函数子查询 等导致“一行不对应基表一行”的情况。
  • 没有 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 VIEWCREATE 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”过一遍后,你就能用视图简化常用查询、隐藏部分列或行。建议在本地按上面的示例建好几类视图(单表、多表、带聚合),再 SELECTSHOW CREATE VIEWDESC 多试几次,巩固视图的用法。

发表评论