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

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


前言

  • 在前几期博客中,我们探讨了 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

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

相关推荐
京东云开发者6 分钟前
Java的SPI机制详解
java
超级小忍28 分钟前
服务端向客户端主动推送数据的几种方法(Spring Boot 环境)
java·spring boot·后端
没有了遇见28 分钟前
Android 渐变色实现总结
android
程序无bug32 分钟前
Spring IoC注解式开发无敌详细(细节丰富)
java·后端
小莫分享34 分钟前
Java Lombok 入门
java
程序无bug34 分钟前
Spring 对于事务上的应用的详细说明
java·后端
食亨技术团队35 分钟前
被忽略的 SAAS 生命线:操作日志有多重要
java·后端
宇钶宇夕38 分钟前
EPLAN 电气制图:建立自己的部件库,添加部件-加SQL Server安装教程(三)上
运维·服务器·数据库·程序人生·自动化
苦学编程的谢1 小时前
Maven
java·maven·intellij-idea
考虑考虑1 小时前
Maven 依赖范围(Scope)
java·后端·maven