数据库系统概论(十五)数据库视图
- 前言
- 一、什么是视图?
- 二、视图的作用
-
- [1. 保护数据安全](#1. 保护数据安全)
- [2. 屏蔽表结构变化](#2. 屏蔽表结构变化)
- [3. 简化复杂查询](#3. 简化复杂查询)
- [4. 多角度展示数据](#4. 多角度展示数据)
- 三、如何创建视图?
- 四、更新视图的限制
- 五、如何删除视图
- 六、查询视图
-
- [1. 查询视图的基本用法](#1. 查询视图的基本用法)
- [2. 系统如何执行视图查询?](#2. 系统如何执行视图查询?)
- 3、复杂视图查询的坑
- 4、不同数据库的差异
- 七、更新视图
-
- [1. 什么是更新视图?](#1. 什么是更新视图?)
- [2. 如何更新视图?](#2. 如何更新视图?)
- [3. 更新视图的"安全锁":WITH CHECK OPTION](#3. 更新视图的“安全锁”:WITH CHECK OPTION)
- [4. 哪些视图不能更新?](#4. 哪些视图不能更新?)
前言
- 在前几期博客中,我们探讨了 SQL 连接查询,单表查询,嵌套查询,集合查询,基于派生表的查询,数据插入,修改与删除,空值的处理技术等知识点。
- 从本节开始,我们将深入讲解 SQL 中视图的知识点。
我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343我的数据库系统概论专栏
https://blog.csdn.net/2402_83322742/category_12911520.html?spm=1001.2014.3001.5482
一、什么是视图?
视图就像数据库中的"虚拟表格" ,它的数据来自真实的表(基表),但本身不存储真实数据,只存储"如何从基表取数据的规则"。
-
举个例子 :
基表是"学生表"(包含所有学生信息 ),视图可以是"信息管理专业学生视图",只显示该专业学生的部分信息(如学号、姓名、专业)。 -
视图的特点:
- 虚表 :数据字典只存定义,不存实际数据。
- 动态更新:基表数据变了,视图查询结果也会变。
二、视图的作用
1. 保护数据安全
- 作用 :控制用户能看到的数据范围,隐藏敏感信息 。
- 举例:员工表中,普通员工只能通过视图看到姓名和部门,而工资、银行卡号等机密字段被"过滤"掉。
- 原理:通过视图限制查询的字段或行,就像给数据加了一层"滤镜",非授权数据无法被访问。
2. 屏蔽表结构变化
- 作用 :当数据库表结构调整(如重命名字段、拆分表)时,视图可以保持对外接口不变,避免影响应用程序。
- 举例:原表
Student
有字段S_age
,改为S_birthdate
后,通过视图依然以S_age
名称提供年龄数据(视图内部转换计算),程序无需修改代码。
- 举例:原表
- 原理:视图作为"中间层",隔离了底层表的变化。
3. 简化复杂查询
- 作用 :将常用的复杂查询(如多表连接、计算字段)定义为视图,用户直接查询视图即可,无需重复写冗长SQL。
- 举例:查询"学生姓名+课程成绩"需要连接
Student
和SC
表,定义视图Student_Score
后,直接查视图就行,不用每次写JOIN
语句。
- 举例:查询"学生姓名+课程成绩"需要连接
- 原理:视图相当于把复杂操作"打包"成一个快捷按钮,点击即可得到结果,减少重复劳动。
4. 多角度展示数据
- 作用 :同一批数据,不同用户可以通过不同视图看到不同角度的内容。
- 举例:销售数据中,普通员工 视图显示"个人业绩明细",经理视图 显示"部门业绩汇总",数据来源相同但展示形式不同。
- 原理:视图就像"数据滤镜",根据用户需求过滤、重组数据,让不同人看到自己需要的信息。
三、如何创建视图?
语法格式:
sql
CREATE VIEW 视图名 [(列名1, 列名2, ...)] -- 可选,定义视图的列名
AS
子查询 -- 从基表取数据的规则(不能有ORDER BY和DISTINCT)
[WITH CHECK OPTION] -- 可选,限制通过视图更新数据时必须符合子查询条件
5种常见视图类型:
-
行列子集视图(单表筛选)
场景:从"学生表"筛选"信息管理专业"学生,只显示部分列。sqlCREATE VIEW IS_Student AS SELECT Sno, Sname, Ssex, Smajor -- 选这几列 FROM Student -- 基表 WHERE Smajor = '信息管理与信息系统'; -- 筛选条件
- 说明:省略列名时,视图列名和子查询的列名一致。
-
多表视图(多表连接)
场景:查询"信息管理专业学生选81001课程的成绩"(学生表+选课表连接)。sqlCREATE VIEW IS_C1(Sno, Sname, Grade) AS -- 显式指定列名 SELECT Student.Sno, Sname, Grade -- 选学号、姓名、成绩 FROM Student, SC -- 两张表 WHERE Student.Sno = SC.Sno -- 连接条件 AND Smajor = '信息管理与信息系统' -- 专业筛选 AND SC.Cno = '81001'; -- 课程筛选
-
基于视图的视图(视图嵌套)
场景:在"IS_C1视图"基础上,再筛选"成绩≥90分"的学生。sqlCREATE VIEW IS_C2 AS -- 直接基于已有视图创建 SELECT Sno, Sname, Grade FROM IS_C1 WHERE Grade >= 90;
-
带表达式的视图(计算列)
场景:计算学生年龄(用出生日期算年龄)。sqlCREATE VIEW S_AGE(Sno, Sname, Sage) AS -- 必须显式指定列名(含计算列) SELECT Sno, Sname, TIMESTAMPDIFF(YEAR, Sbirthdate, CURDATE()) -- 计算年龄的表达式 FROM Student;
-
分组视图(聚合函数)
场景:统计每个学生的平均成绩。sqlCREATE VIEW S_GradeAVG(Sno, Gavg) AS -- 显式指定列名(含聚合列) SELECT Sno, AVG(Grade) -- 按学号分组,算平均成绩 FROM SC GROUP BY Sno;
四、更新视图的限制
-
一般情况:视图主要用于查询,直接增删改可能受限(因视图可能关联多表或包含表达式)。
-
强制限制 :创建视图时加
WITH CHECK OPTION
,可确保通过视图插入/修改的数据符合视图定义的条件。sqlCREATE VIEW IS_Student AS SELECT ... FROM Student WHERE Smajor='信息管理与信息系统' WITH CHECK OPTION; -- 插入时若专业不是该专业,会报错
五、如何删除视图
语法:
sql
DROP VIEW 视图名 [CASCADE]; -- CASCADE(级联删除):删除依赖它的其他视图
-
例子 :
-
单删视图:
DROP VIEW S_AGE;
-
级联删(如IS_C1视图被IS_C2依赖):
sqlDROP VIEW IS_C1 CASCADE; -- 同时删除IS_C1和IS_C2
-
-
注意 :不同数据库差异大!
- KingBase支持
CASCADE
级联删除; - MySQL不支持,删除IS_C1后,IS_C2会失效但不会自动删除,需手动处理。
- KingBase支持
六、查询视图
1. 查询视图的基本用法
查询视图就像查询普通表一样简单 ,直接写 SELECT
语句即可,语法和查基表完全一致。
-
举例 :
有一个"信息管理专业学生视图"(IS_Student),想查其中年龄≤20岁的学生学号和出生日期:sqlSELECT Sno, Sbirthdate FROM IS_Student WHERE TIMESTAMPDIFF(YEAR, Sbirthdate, CURDATE()) <= 20;
看起来和查基表没区别,但背后系统会做一些转换。
2. 系统如何执行视图查询?
当你查询视图时,数据库系统会做以下三件事:
-
检查有效性:确认视图是否存在,列名是否正确。
-
转换成基表查询 (核心步骤):
-
有一个视图表他的定义是:
sqlCREATE VIEW IS_Student AS SELECT Sno,... FROM Student WHERE Smajor='信息管理与信息系统';
-
系统会把它的视图查询 "翻译"成基表查询 :
sqlSELECT Sno, Sbirthdate FROM Student WHERE Smajor='信息管理与信息系统' -- 视图定义的条件 AND TIMESTAMPDIFF(YEAR, Sbirthdate, CURDATE()) <= 20; -- 你加的条件
-
-
执行翻译后的SQL:直接对基表(Student表)执行查询,返回结果。
核心逻辑:视图查询本质是"披着视图外衣的基表查询",系统会先把视图"还原"成基表的SQL,再执行。
3、复杂视图查询的坑
场景:用分组视图查平均成绩≥90分的学生
假设你有一个分组视图 S_GradeAVG(存储每个学生的学号和平均成绩):
sql
CREATE VIEW S_GradeAVG(Sno, Gavg) AS
SELECT Sno, AVG(Grade) FROM SC GROUP BY Sno;
错误做法 :直接对视图用 WHERE
过滤平均成绩
sql
SELECT * FROM S_GradeAVG WHERE Gavg >= 90; -- 看似正确,实则错误!
系统翻译后:
sql
SELECT Sno, AVG(Grade) FROM SC
WHERE AVG(Grade) >= 90 -- ❌ WHERE子句不能用聚集函数(AVG)
GROUP BY Sno;
报错原因 :WHERE
只能过滤行数据,不能直接用聚集函数(如AVG、SUM),聚集函数要配合 HAVING
使用。
正确做法1:直接对基表查询(用HAVING)
sql
SELECT Sno, AVG(Grade) AS Gavg FROM SC
GROUP BY Sno
HAVING Gavg >= 90; -- ✅ 用HAVING过滤分组后的结果
正确做法2:用派生表模拟视图(临时视图)
sql
SELECT * FROM (
SELECT Sno, AVG(Grade) AS Gavg FROM SC GROUP BY Sno
) AS 临时视图名 -- 派生表,执行完就消失
WHERE Gavg >= 90;
4、不同数据库的差异
- 视图查询的兼容性 :
- 大部分数据库(如KingBase)对简单视图(行列子集视图)能正确翻译,但复杂视图(如分组视图)可能报错。
- MySQL比较"宽容" :
-
对分组视图的
WHERE Gavg >= 80
可能能执行(内部做了优化),但本质上不推荐这么写。 -
直接对基表用
WHERE AVG(Grade)
会报错:sqlSELECT Sno, AVG(Grade) FROM SC WHERE AVG(Grade) >= 90 GROUP BY Sno; -- ❌ MySQL报错!
-
七、更新视图
1. 什么是更新视图?
通过视图修改基表的数据(增、删、改)。
- 本质:视图本身没有数据,更新视图时,数据库会把操作"翻译"成对基表的更新(视图消解)。
- 举例:修改视图中的学生姓名,其实是在修改基表(学生表)中的真实数据。
2. 如何更新视图?
(1)修改数据
场景:将IS_Student视图中学号为20180005的学生姓名改为"刘新奇"。
sql
UPDATE IS_Student SET Sname='刘新奇' WHERE Sno='20180005';
背后发生了什么?
数据库自动将视图查询转换为基表操作:
sql
UPDATE Student SET Sname='刘新奇'
WHERE Sno='20180005' AND Smajor='信息管理与信息系统'; -- 视图定义的条件自动保留
(2)插入数据
场景:向IS_Student视图中插入一个信息管理专业的学生。
sql
INSERT INTO IS_Student VALUES ('20180207','赵新','男','2001-7-19','信息管理与信息系统');
背后发生了什么?
直接插入基表(Student表),专业字段自动符合视图条件:
sql
INSERT INTO Student VALUES ('20180207','赵新','男','2001-7-19','信息管理与信息系统');
(3)删除数据
场景:删除IS_Student视图中学号为20180207的学生。
sql
DELETE FROM IS_Student WHERE Sno='20180207';
背后发生了什么?
从基表删除符合条件的记录(同时满足学号和专业条件):
sql
DELETE FROM Student WHERE Sno='20180207' AND Smajor='信息管理与信息系统';
3. 更新视图的"安全锁":WITH CHECK OPTION
作用:确保通过视图插入/修改的数据必须符合视图定义的条件,防止"脏数据"进入。
-
创建视图时加锁 :
sqlCREATE VIEW IS_Student AS SELECT ... FROM Student WHERE Smajor='信息管理与信息系统' WITH CHECK OPTION; -- 强制要求插入/修改的记录必须是该专业
-
举例 :
若尝试插入其他专业的学生:sqlINSERT INTO IS_Student VALUES ('20180208','钱明','男',...,'计算机科学与技术');
结果 :直接报错,因为违反了
WITH CHECK OPTION
的条件(专业必须是信息管理与信息系统)。
4. 哪些视图不能更新?
(1)复杂视图
-
包含多表连接的视图 :
例:基于学生表和选课表连接创建的视图,无法确定更新哪张表的数据。 -
包含聚集函数的视图 (如AVG、SUM):
例:S_GradeAVG视图(平均成绩),更新平均分会导致逻辑混乱(系统不知道要改哪些原始成绩)。sqlUPDATE S_GradeAVG SET Gavg=90 WHERE Sno='20180001'; -- ❌ 报错!
-
分组视图 (含GROUP BY):
同上,系统无法将分组后的更新映射到基表的具体行。
(2)不同数据库的限制差异
- 行列子集视图(单表简单筛选):通常可以更新(如IS_Student视图)。
- 非行列子集视图 :不同数据库处理不同,例如:
- MySQL可能允许部分更新,但不推荐;
- KingBase等严格数据库会直接禁止复杂视图的更新。
以上就是这篇博客的全部内容,下一篇我们将继续探索更多精彩内容。
我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343我的数据库系统概论专栏
https://blog.csdn.net/2402_83322742/category_12911520.html?spm=1001.2014.3001.5482
|--------------------|
| 非常感谢您的阅读,喜欢的话记得三连哦 |
