数据库系统概论(十五)详细讲解数据库视图

数据库系统概论(十五)数据库视图


前言

  • 在前几期博客中,我们探讨了 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. 动态更新:基表数据变了,视图查询结果也会变。

二、视图的作用

1. 保护数据安全

  • 作用控制用户能看到的数据范围,隐藏敏感信息
    • 举例:员工表中,普通员工只能通过视图看到姓名和部门,而工资、银行卡号等机密字段被"过滤"掉。
  • 原理:通过视图限制查询的字段或行,就像给数据加了一层"滤镜",非授权数据无法被访问。

2. 屏蔽表结构变化

  • 作用 :当数据库表结构调整(如重命名字段、拆分表)时,视图可以保持对外接口不变,避免影响应用程序。
    • 举例:原表Student有字段S_age,改为S_birthdate后,通过视图依然以S_age名称提供年龄数据(视图内部转换计算),程序无需修改代码。
  • 原理:视图作为"中间层",隔离了底层表的变化。

3. 简化复杂查询

  • 作用 :将常用的复杂查询(如多表连接、计算字段)定义为视图,用户直接查询视图即可,无需重复写冗长SQL。
    • 举例:查询"学生姓名+课程成绩"需要连接StudentSC表,定义视图Student_Score后,直接查视图就行,不用每次写JOIN语句。
  • 原理:视图相当于把复杂操作"打包"成一个快捷按钮,点击即可得到结果,减少重复劳动。

4. 多角度展示数据

  • 作用 :同一批数据,不同用户可以通过不同视图看到不同角度的内容。
    • 举例:销售数据中,普通员工 视图显示"个人业绩明细",经理视图 显示"部门业绩汇总",数据来源相同但展示形式不同。
  • 原理:视图就像"数据滤镜",根据用户需求过滤、重组数据,让不同人看到自己需要的信息。

三、如何创建视图?

语法格式:

sql 复制代码
CREATE VIEW 视图名 [(列名1, 列名2, ...)] -- 可选,定义视图的列名
AS
子查询 -- 从基表取数据的规则(不能有ORDER BY和DISTINCT)
[WITH CHECK OPTION] -- 可选,限制通过视图更新数据时必须符合子查询条件

5种常见视图类型:

  1. 行列子集视图(单表筛选)
    场景:从"学生表"筛选"信息管理专业"学生,只显示部分列。

    sql 复制代码
    CREATE VIEW IS_Student AS
    SELECT Sno, Sname, Ssex, Smajor -- 选这几列
    FROM Student -- 基表
    WHERE Smajor = '信息管理与信息系统'; -- 筛选条件
    • 说明:省略列名时,视图列名和子查询的列名一致。
  2. 多表视图(多表连接)
    场景:查询"信息管理专业学生选81001课程的成绩"(学生表+选课表连接)。

    sql 复制代码
    CREATE 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'; -- 课程筛选
  3. 基于视图的视图(视图嵌套)
    场景:在"IS_C1视图"基础上,再筛选"成绩≥90分"的学生。

    sql 复制代码
    CREATE VIEW IS_C2 AS -- 直接基于已有视图创建
    SELECT Sno, Sname, Grade 
    FROM IS_C1 
    WHERE Grade >= 90;
  4. 带表达式的视图(计算列)
    场景:计算学生年龄(用出生日期算年龄)。

    sql 复制代码
    CREATE VIEW S_AGE(Sno, Sname, Sage) AS -- 必须显式指定列名(含计算列)
    SELECT Sno, Sname, 
           TIMESTAMPDIFF(YEAR, Sbirthdate, CURDATE()) -- 计算年龄的表达式
    FROM Student;
  5. 分组视图(聚合函数)
    场景:统计每个学生的平均成绩。

    sql 复制代码
    CREATE VIEW S_GradeAVG(Sno, Gavg) AS -- 显式指定列名(含聚合列)
    SELECT Sno, AVG(Grade) -- 按学号分组,算平均成绩
    FROM SC 
    GROUP BY Sno;

四、更新视图的限制

  • 一般情况:视图主要用于查询,直接增删改可能受限(因视图可能关联多表或包含表达式)。

  • 强制限制 :创建视图时加 WITH CHECK OPTION,可确保通过视图插入/修改的数据符合视图定义的条件。

    sql 复制代码
    CREATE 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依赖):

      sql 复制代码
      DROP VIEW IS_C1 CASCADE; -- 同时删除IS_C1和IS_C2
  • 注意 :不同数据库差异大!

    • KingBase支持CASCADE级联删除;
    • MySQL不支持,删除IS_C1后,IS_C2会失效但不会自动删除,需手动处理。

六、查询视图

1. 查询视图的基本用法

查询视图就像查询普通表一样简单 ,直接写 SELECT 语句即可,语法和查基表完全一致。

  • 举例
    有一个"信息管理专业学生视图"(IS_Student),想查其中年龄≤20岁的学生学号和出生日期:

    sql 复制代码
    SELECT Sno, Sbirthdate FROM IS_Student 
    WHERE TIMESTAMPDIFF(YEAR, Sbirthdate, CURDATE()) <= 20;

    看起来和查基表没区别,但背后系统会做一些转换。

2. 系统如何执行视图查询?

当你查询视图时,数据库系统会做以下三件事

  1. 检查有效性:确认视图是否存在,列名是否正确。

  2. 转换成基表查询 (核心步骤):

    • 有一个视图表他的定义是:

      sql 复制代码
      CREATE VIEW IS_Student AS 
      SELECT Sno,... FROM Student WHERE Smajor='信息管理与信息系统';
    • 系统会把它的视图查询 "翻译"成基表查询

      sql 复制代码
      SELECT Sno, Sbirthdate FROM Student 
      WHERE Smajor='信息管理与信息系统'  -- 视图定义的条件
        AND TIMESTAMPDIFF(YEAR, Sbirthdate, CURDATE()) <= 20;  -- 你加的条件
  3. 执行翻译后的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、不同数据库的差异

  1. 视图查询的兼容性
    • 大部分数据库(如KingBase)对简单视图(行列子集视图)能正确翻译,但复杂视图(如分组视图)可能报错。
    • MySQL比较"宽容"
      • 对分组视图的 WHERE Gavg >= 80 可能能执行(内部做了优化),但本质上不推荐这么写。

      • 直接对基表用 WHERE AVG(Grade) 会报错:

        sql 复制代码
        SELECT 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

作用:确保通过视图插入/修改的数据必须符合视图定义的条件,防止"脏数据"进入。

  • 创建视图时加锁

    sql 复制代码
    CREATE VIEW IS_Student AS
    SELECT ... FROM Student WHERE Smajor='信息管理与信息系统'
    WITH CHECK OPTION; -- 强制要求插入/修改的记录必须是该专业
  • 举例
    若尝试插入其他专业的学生:

    sql 复制代码
    INSERT INTO IS_Student VALUES ('20180208','钱明','男',...,'计算机科学与技术');

    结果 :直接报错,因为违反了WITH CHECK OPTION的条件(专业必须是信息管理与信息系统)。

4. 哪些视图不能更新?

(1)复杂视图

  • 包含多表连接的视图
    例:基于学生表和选课表连接创建的视图,无法确定更新哪张表的数据。

  • 包含聚集函数的视图 (如AVG、SUM):
    例:S_GradeAVG视图(平均成绩),更新平均分会导致逻辑混乱(系统不知道要改哪些原始成绩)。

    sql 复制代码
    UPDATE 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

|--------------------|
| 非常感谢您的阅读,喜欢的话记得三连哦 |

相关推荐
jiet_h3 小时前
Android Kotlin 算法详解:链表相关
android·算法·kotlin
数据潜水员4 小时前
C#基础语法
java·jvm·算法
你这个代码我看不懂4 小时前
Java项目OOM排查
java·开发语言
Zong_09154 小时前
AutoCompose - 携程自动编排【开源】
java·spring boot·开源·自动编排
@老蝴4 小时前
C语言 — 动态内存管理
android·c语言·开发语言
heart000_15 小时前
MySQL事务与锁机制详解:确保数据一致性的关键【MySQL系列】
数据库·mysql
.生产的驴5 小时前
SpringCloud 分布式锁Redisson锁的重入性与看门狗机制 高并发 可重入
java·分布式·后端·spring·spring cloud·信息可视化·tomcat
一眼青苔5 小时前
MySQL 如何判断某个表中是否存在某个字段
数据库·mysql
虾球xz5 小时前
CppCon 2014 学习:C++ Memory Model Meets High-Update-Rate Data Structures
java·开发语言·c++·学习
攒了一袋星辰5 小时前
Spring @Autowired自动装配的实现机制
java·后端·spring