我的个人主页,欢迎来阅读我的其他文章
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
视图就像数据库中的“虚拟表格”,它的数据来自真实的表(基表),但本身不存储真实数据,只存储“如何从基表取数据的规则”。
举个例子:
基表是“学生表”(包含所有学生信息),视图可以是“信息管理专业学生视图”,只显示该专业学生的部分信息(如学号、姓名、专业)。
视图的特点:
Student
有字段S_age
,改为S_birthdate
后,通过视图依然以S_age
名称提供年龄数据(视图内部转换计算),程序无需修改代码。Student
和SC
表,定义视图Student_Score
后,直接查视图就行,不用每次写JOIN
语句。CREATE VIEW 视图名 [(列名1, 列名2, ...)] -- 可选,定义视图的列名
AS
子查询 -- 从基表取数据的规则(不能有ORDER BY和DISTINCT)
[WITH CHECK OPTION] -- 可选,限制通过视图更新数据时必须符合子查询条件
行列子集视图(单表筛选)
场景:从“学生表”筛选“信息管理专业”学生,只显示部分列。
CREATE VIEW IS_Student AS
SELECT Sno, Sname, Ssex, Smajor -- 选这几列
FROM Student -- 基表
WHERE Smajor = '信息管理与信息系统'; -- 筛选条件
多表视图(多表连接)
场景:查询“信息管理专业学生选81001课程的成绩”(学生表+选课表连接)。
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'; -- 课程筛选
基于视图的视图(视图嵌套)
场景:在“IS_C1视图”基础上,再筛选“成绩≥90分”的学生。
CREATE VIEW IS_C2 AS -- 直接基于已有视图创建
SELECT Sno, Sname, Grade
FROM IS_C1
WHERE Grade >= 90;
带表达式的视图(计算列)
场景:计算学生年龄(用出生日期算年龄)。
CREATE VIEW S_AGE(Sno, Sname, Sage) AS -- 必须显式指定列名(含计算列)
SELECT Sno, Sname,
TIMESTAMPDIFF(YEAR, Sbirthdate, CURDATE()) -- 计算年龄的表达式
FROM Student;
分组视图(聚合函数)
场景:统计每个学生的平均成绩。
CREATE VIEW S_GradeAVG(Sno, Gavg) AS -- 显式指定列名(含聚合列)
SELECT Sno, AVG(Grade) -- 按学号分组,算平均成绩
FROM SC
GROUP BY Sno;
WITH CHECK OPTION
,可确保通过视图插入/修改的数据符合视图定义的条件。CREATE VIEW IS_Student AS
SELECT ... FROM Student WHERE Smajor='信息管理与信息系统'
WITH CHECK OPTION; -- 插入时若专业不是该专业,会报错
语法:
DROP VIEW 视图名 [CASCADE]; -- CASCADE(级联删除):删除依赖它的其他视图
DROP VIEW S_AGE;
DROP VIEW IS_C1 CASCADE; -- 同时删除IS_C1和IS_C2
CASCADE
级联删除;查询视图就像查询普通表一样简单,直接写 SELECT
语句即可,语法和查基表完全一致。
SELECT Sno, Sbirthdate FROM IS_Student
WHERE TIMESTAMPDIFF(YEAR, Sbirthdate, CURDATE()) <= 20;
看起来和查基表没区别,但背后系统会做一些转换。当你查询视图时,数据库系统会做以下三件事:
CREATE VIEW IS_Student AS
SELECT Sno,... FROM Student WHERE Smajor='信息管理与信息系统';
SELECT Sno, Sbirthdate FROM Student
WHERE Smajor='信息管理与信息系统' -- 视图定义的条件
AND TIMESTAMPDIFF(YEAR, Sbirthdate, CURDATE()) <= 20; -- 你加的条件
核心逻辑:视图查询本质是“披着视图外衣的基表查询”,系统会先把视图“还原”成基表的SQL,再执行。
假设你有一个分组视图 S_GradeAVG(存储每个学生的学号和平均成绩):
CREATE VIEW S_GradeAVG(Sno, Gavg) AS
SELECT Sno, AVG(Grade) FROM SC GROUP BY Sno;
错误做法:直接对视图用 WHERE
过滤平均成绩
SELECT * FROM S_GradeAVG WHERE Gavg >= 90; -- 看似正确,实则错误!
系统翻译后:
SELECT Sno, AVG(Grade) FROM SC
WHERE AVG(Grade) >= 90 -- ❌ WHERE子句不能用聚集函数(AVG)
GROUP BY Sno;
报错原因:WHERE
只能过滤行数据,不能直接用聚集函数(如AVG、SUM),聚集函数要配合 HAVING
使用。
SELECT Sno, AVG(Grade) AS Gavg FROM SC
GROUP BY Sno
HAVING Gavg >= 90; -- ✅ 用HAVING过滤分组后的结果
SELECT * FROM (
SELECT Sno, AVG(Grade) AS Gavg FROM SC GROUP BY Sno
) AS 临时视图名 -- 派生表,执行完就消失
WHERE Gavg >= 90;
WHERE Gavg >= 80
可能能执行(内部做了优化),但本质上不推荐这么写。WHERE AVG(Grade)
会报错:SELECT Sno, AVG(Grade) FROM SC
WHERE AVG(Grade) >= 90 GROUP BY Sno; -- ❌ MySQL报错!
通过视图修改基表的数据(增、删、改)。
场景:将IS_Student视图中学号为20180005的学生姓名改为“刘新奇”。
UPDATE IS_Student SET Sname='刘新奇' WHERE Sno='20180005';
背后发生了什么?
数据库自动将视图查询转换为基表操作:
UPDATE Student SET Sname='刘新奇'
WHERE Sno='20180005' AND Smajor='信息管理与信息系统'; -- 视图定义的条件自动保留
场景:向IS_Student视图中插入一个信息管理专业的学生。
INSERT INTO IS_Student VALUES ('20180207','赵新','男','2001-7-19','信息管理与信息系统');
背后发生了什么?
直接插入基表(Student表),专业字段自动符合视图条件:
INSERT INTO Student VALUES ('20180207','赵新','男','2001-7-19','信息管理与信息系统');
场景:删除IS_Student视图中学号为20180207的学生。
DELETE FROM IS_Student WHERE Sno='20180207';
背后发生了什么?
从基表删除符合条件的记录(同时满足学号和专业条件):
DELETE FROM Student WHERE Sno='20180207' AND Smajor='信息管理与信息系统';
作用:确保通过视图插入/修改的数据必须符合视图定义的条件,防止“脏数据”进入。
CREATE VIEW IS_Student AS
SELECT ... FROM Student WHERE Smajor='信息管理与信息系统'
WITH CHECK OPTION; -- 强制要求插入/修改的记录必须是该专业
INSERT INTO IS_Student VALUES ('20180208','钱明','男',...,'计算机科学与技术');
结果:直接报错,因为违反了WITH CHECK OPTION
的条件(专业必须是信息管理与信息系统)。UPDATE S_GradeAVG SET Gavg=90 WHERE Sno='20180001'; -- ❌ 报错!
以上就是这篇博客的全部内容,下一篇我们将继续探索更多精彩内容。
我的个人主页,欢迎来阅读我的其他文章
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
非常感谢您的阅读,喜欢的话记得三连哦 |