openGauss 视图零基础实战教程
本教程基于 openGauss 数据库,结合配套的医院业务表,从入门到实操完整讲解视图的核心知识、操作方法与实战技巧,配套连贯业务案例与生活化解读,零基础可直接上手执行。
一、初识视图:到底什么是视图?
1.1 核心定义
生活化类比:视图就像电脑里的文件快捷方式、医院的定制化看板。快捷方式本身不存文件内容,只存文件的访问路径;视图本身不存储任何真实数据,数据库里只存视图的定义(一条 SELECT 查询语句),当你查询视图时,数据库会自动执行这条查询,从底层的「基本表」(真实存数据的表)中实时取出数据。
官方定义:视图是 openGauss 中的虚拟表,和真实数据表一样具备命名的列和数据行,但数据全部来自于基本表的查询结果,数据库仅存储视图的定义语句,不存储视图对应的数据。
核心组成:视图名 + 视图定义(SELECT 查询语句)
1.2 用视图的 3 大核心优势
简化复杂查询,告别重复代码
业务场景:每次查询患者挂号完整信息,都要写 3 表 JOIN 的长 SQL,重复繁琐。
解决方案:把固定的 JOIN 查询做成视图,后续只需SELECT * FROM 视图名即可拿到结果,无需重复写长 SQL。
生活化举例:就像把常用的 Excel 公式存成模板,下次直接调用,不用重新敲写全量公式。精细化权限控制,保障数据安全
业务场景:医院导诊、实习生需要看医生的姓名、科室、职称,但绝对不能查看医生薪资;财务仅能看薪资统计,不能修改患者信息。
解决方案:给不同角色创建专属视图,仅开放其需要的字段,仅授予角色视图的查询权限,不开放底层基本表的权限,从根源避免敏感数据泄露。
生活化举例:就像银行柜员只能看到你的账户基本信息,看不到完整征信报告,银行给柜员开放的就是一个「权限受限的视图」。屏蔽表结构变化,提升数据独立性
业务场景:后续科室表his_dpt要新增「科室电话」「科室主任」字段,原有写好的查询语句很可能报错失效。
解决方案:基于视图的查询不会受底层表新增字段的影响,只要视图用到的字段无变化,业务代码完全无需修改。
生活化举例:就像你给文件换了存储文件夹,只要更新快捷方式的路径,双击仍能正常打开文件,无需关心文件的实际存储位置。
太官方了 我有点懵?!
二、视图核心管理:创建、查看、修改、删除
本章节全程使用配套的医院业务表(科室表his_dpt、医生表his_emp、挂号表his_reg、药品表his_drug),案例从简单到复杂,覆盖所有常用场景,所有 SQL 均适配 openGauss 官方语法,可直接复制执行。
命名规范:所有视图统一加
v_前缀,与普通表区分,避免重名(openGauss 同库中视图名不能与表名重复)。
2.1 创建视图:CREATE VIEW 语法全解析
2.1.1 基础语法
CREATE [OR REPLACE] VIEW <视图名>[(<列名1>[,<列名2>]...)]
[WITH ENCRYPTION]
AS <SELECT查询语句>
[WITH CHECK OPTION];
2.1.2 关键参数通俗解读
| 参数 | 核心作用 | 生活化解释 |
|---|---|---|
| OR REPLACE | 视图已存在时直接覆盖,无需先删除再创建 | 等同于文件的「覆盖保存」,不用先删旧文件再存新文件 |
| WITH ENCRYPTION | 加密视图定义语句,加密后用户无法查看视图源码 | 给视图定义加密码锁,防止他人查看核心查询逻辑 |
| WITH CHECK OPTION | 强制通过视图增删改的数据,必须满足视图 SELECT 中的 WHERE 条件 | 给看板加准入规则,只能往心内科的看板里添加心内科医生,无法添加其他科室数据 |
| 自定义列名 | 给视图列起别名,无需与底层表列名一致 | 给看板列起用户易懂的名称,比如把emp_name改为「医生姓名」 |
2.1.3 分场景创建案例(循序渐进,贯穿全表)
案例 1:基于单表的基础视图(最简入门)
业务需求:给医院大厅做科室导览视图,仅显示科室名称和所在位置,不暴露后台科室编码等内部字段。
-- 创建视图
CREATE VIEW v_dpt_guide
AS
SELECT dpt_name 科室名称, location 所在位置
FROM his_dpt;
-- 查询视图,语法与查询普通表完全一致
SELECT * FROM v_dpt_guide;
执行结果:
| 科室名称 | 所在位置 |
|---|---|
| 心内科 | 门诊楼 2 层 |
| 普外科 | 门诊楼 3 层 |
| 急诊科 | 门诊楼 1 层 |
| 儿科 | 门诊楼 4 层 |
案例 2:带条件过滤 + 权限控制的单表视图
业务需求:给心内科主任创建视图,仅能查看心内科医生信息,隐藏敏感薪资字段,同时限制只能操作心内科数据。
-- 创建视图,自定义列名,加WHERE条件与WITH CHECK OPTION
CREATE VIEW v_nei01_doctor(医生编号, 医生姓名, 职称)
AS
SELECT emp_id, emp_name, title
FROM his_emp
WHERE dpt_code = 'NEI01'
WITH CHECK OPTION;
-- 查询视图
SELECT * FROM v_nei01_doctor;
执行结果:
| 医生编号 | 医生姓名 | 职称 |
|---|---|---|
| 1 | 张医生 | 主任 |
| 3 | 王医生 | 主治 |
关键说明:加了WITH CHECK OPTION后,通过该视图插入 / 修改的数据,必须满足dpt_code = 'NEI01',否则直接报错,从根源防止数据越权。
案例 3:基于多表关联的视图(最常用场景)
业务需求:给挂号处做一站式挂号详情视图,无需每次写多表 JOIN,直接查看挂号单号、患者姓名、接诊医生、所属科室、挂号费。
-- 创建多表关联视图,关联挂号表、医生表、科室表
CREATE VIEW v_reg_detail
AS
SELECT
a.reg_id 挂号单号,
a.pat_name 患者姓名,
b.emp_name 接诊医生,
c.dpt_name 所属科室,
a.reg_fee 挂号费
FROM his_reg a
LEFT JOIN his_emp b ON a.emp_id = b.emp_id
LEFT JOIN his_dpt c ON b.dpt_code = c.dpt_code;
-- 查询视图
SELECT * FROM v_reg_detail;
执行结果:
| 挂号单号 | 患者姓名 | 接诊医生 | 所属科室 | 挂号费 |
|---|---|---|---|---|
| 1 | 患者甲 | 张医生 | 心内科 | 50.00 |
| 2 | 患者乙 | 张医生 | 心内科 | 50.00 |
| 3 | 患者丙 | 李医生 | 普外科 | 40.00 |
| 4 | 患者丁 | 王医生 | 心内科 | 30.00 |
| 5 | 患者戊 | 赵医生 | 急诊科 | 30.00 |
案例 4:基于统计 + 分组的聚合视图
业务需求:给财务科做科室挂号统计视图,自动计算每个科室的接诊人次、挂号总收入、平均挂号费。
-- 创建分组统计视图
CREATE VIEW v_dpt_reg_stat(科室名称, 接诊人次, 挂号总收入, 平均挂号费)
AS
SELECT
c.dpt_name,
COUNT(a.reg_id),
SUM(a.reg_fee),
AVG(a.reg_fee)
FROM his_reg a
LEFT JOIN his_emp b ON a.emp_id = b.emp_id
LEFT JOIN his_dpt c ON b.dpt_code = c.dpt_code
GROUP BY c.dpt_name;
-- 查询视图
SELECT * FROM v_dpt_reg_stat;
执行结果:
| 科室名称 | 接诊人次 | 挂号总收入 | 平均挂号费 |
|---|---|---|---|
| 心内科 | 3 | 130.00 | 43.333333 |
| 普外科 | 1 | 40.00 | 40.000000 |
| 急诊科 | 1 | 30.00 | 30.000000 |
案例 5:基于视图的视图(视图嵌套)
业务需求:在挂号详情视图v_reg_detail的基础上,给心内科创建专属挂号记录视图,无需重新写多表 JOIN,直接复用已有视图。
-- 基于已有视图创建新视图
CREATE VIEW v_nei01_reg
AS
SELECT * FROM v_reg_detail
WHERE 所属科室 = '心内科';
-- 查询视图
SELECT * FROM v_nei01_reg;
执行结果:
| 挂号单号 | 患者姓名 | 接诊医生 | 所属科室 | 挂号费 |
|---|---|---|---|---|
| 1 | 患者甲 | 张医生 | 心内科 | 50.00 |
| 2 | 患者乙 | 张医生 | 心内科 | 50.00 |
| 4 | 患者丁 | 王医生 | 心内科 | 30.00 |
2.1.4 openGauss 创建视图的注意事项
权限要求:创建视图的用户必须拥有
CREATE VIEW权限,同时对视图定义中 SELECT 涉及的表 / 列拥有SELECT权限;使用OR REPLACE时,还需要拥有视图的DROP权限。存储位置:默认创建在当前连接的数据库中,若要指定数据库,可写为
CREATE VIEW 数据库名\.视图名。加密视图:
WITH ENCRYPTION创建的加密视图,无法通过系统表查看定义,仅高权限用户可操作,适合敏感业务场景。
2.2 查看视图:openGauss 查看已创建视图的方法
方式 1:gsql 客户端命令行查看(最快捷)
-- 查看当前库下所有视图
\dv
-- 查看视图的详细结构(包含字段、类型、依赖关系)
\d+ v_reg_detail
方式 2:通过系统表查询(通用,适配所有客户端)
-- 查看指定视图的定义
SELECT * FROM pg_views WHERE viewname = 'v_nei01_doctor';
-- 查看当前用户拥有的所有视图
SELECT * FROM pg_views WHERE schemaname = 'public';
2.3 修改视图:两种核心方式
openGauss 中修改视图主要有 2 种方式,适配不同场景:
场景 1:修改视图的查询逻辑(核心定义)
使用CREATE OR REPLACE VIEW直接覆盖原有视图,无需先删除,是最常用的修改方式。
业务需求:给v_nei01_doctor视图新增「所属科室」字段,修改原有视图。
-- 覆盖修改视图
CREATE OR REPLACE VIEW v_nei01_doctor(医生编号, 医生姓名, 职称, 所属科室)
AS
SELECT emp_id, emp_name, title, dpt_code
FROM his_emp
WHERE dpt_code = 'NEI01'
WITH CHECK OPTION;
-- 查询验证
SELECT * FROM v_nei01_doctor;
场景 2:修改视图的属性(名称、所有者、备注等)
使用ALTER VIEW语句,仅修改视图属性,不修改核心查询定义。
-- 1. 修改视图名称
ALTER VIEW v_nei01_doctor RENAME TO v_nei01_doc;
-- 2. 修改视图的所有者
ALTER VIEW v_nei01_doc OWNER TO 新用户名;
-- 3. 设置视图的备注
COMMENT ON VIEW v_nei01_doc IS '心内科医生信息视图';
2.4 删除视图:DROP VIEW 语法
视图不再使用时,可通过DROP VIEW语句删除,语法如下:
-- 基础语法
DROP VIEW [IF EXISTS] 视图名1 [, 视图名2...] [CASCADE | RESTRICT];
关键参数说明
IF EXISTS:视图不存在时不会报错,仅给出提示,避免脚本执行中断,推荐日常使用。CASCADE:级联删除,同时删除依赖于当前视图的其他视图(比如v_nei01_reg依赖v_reg_detail,删除v_reg_detail时加CASCADE会同步删除v_nei01_reg)。RESTRICT:限制删除(默认值),如果有其他视图依赖当前视图,会报错禁止删除,防止误删。
实操案例
-- 1. 安全删除单个视图(推荐)
DROP VIEW IF EXISTS v_dpt_guide;
-- 2. 批量删除多个视图
DROP VIEW IF EXISTS v_nei01_doc, v_dpt_reg_stat;
-- 3. 级联删除有依赖的视图
DROP VIEW IF EXISTS v_reg_detail CASCADE;
三、视图数据操作:通过视图增删改底层表数据
视图是虚拟表,本身不存储数据,通过视图执行INSERT/UPDATE/DELETE,最终都会作用到底层的基本表上。但并非所有视图都能执行数据操作,有严格的限制条件。
3.1 可操作视图的核心前提
只有基于单表、无聚合函数、无分组 / 去重、包含基本表所有非空约束字段的视图,才能正常执行增删改操作;多表视图、聚合视图等一般无法执行数据操作。
3.2 插入数据:通过视图 INSERT
成功案例:单表视图插入
业务需求:通过基础视图v_emp_base,新增一名医生信息。
-- 先创建可操作的单表视图,包含所有非空约束字段
CREATE VIEW v_emp_base
AS
SELECT emp_id, emp_name, dpt_code
FROM his_emp
WITH CHECK OPTION;
-- 通过视图插入数据,语法与插入普通表完全一致
INSERT INTO v_emp_base VALUES (7, '周医生', 'PED01');
-- 验证:查询底层基本表,数据已成功插入
SELECT * FROM his_emp WHERE emp_id = 7;
关键约束:WITH CHECK OPTION 的作用
如果视图有 WHERE 过滤条件,加了WITH CHECK OPTION后,插入的数据必须满足 WHERE 条件,否则会报错。
-- 尝试通过心内科视图插入儿科医生,会直接报错
INSERT INTO v_nei01_doctor(医生编号, 医生姓名, 职称, 所属科室)
VALUES (8, '吴医生', '主治', 'PED01');
报错原因:插入的数据不满足视图定义中的dpt_code = 'NEI01'条件,WITH CHECK OPTION阻止了非法数据插入。
3.3 修改数据:通过视图 UPDATE
和插入规则一致,仅可操作单表视图,且修改后的数据必须满足WITH CHECK OPTION的约束条件。
-- 通过视图修改周医生的所属科室
UPDATE v_emp_base SET dpt_code = 'WAI01' WHERE emp_id = 7;
-- 验证修改结果
SELECT * FROM v_emp_base WHERE emp_id = 7;
3.4 删除数据:通过视图 DELETE
仅可操作基于单表、无聚合 / 分组的视图,删除的是底层基本表的数据。
-- 通过视图删除新增的周医生数据
DELETE FROM v_emp_base WHERE emp_id = 7;
-- 验证删除结果
SELECT * FROM his_emp WHERE emp_id = 7;
3.5 这些情况,视图数据操作一定会失败
基于多表关联的视图:比如
v_reg_detail是 3 表 JOIN 的视图,无法执行增删改,因为数据库无法定位要修改的底层表。不满足基本表的非空 / 主键约束:比如视图未包含基本表的主键非空字段,插入时会因主键为空报错,如同给医生建档必须填工号,否则系统无法录入。
视图定义包含聚合函数 / 数学表达式:比如统计视图
v_dpt_reg_stat里有SUM/AVG,无法修改,因为这些数据是计算出来的,不是真实存储的,如同不能直接修改成绩单的平均分,只能修改每个学生的原始分数。视图定义包含 GROUP BY/DISTINCT/UNION/HAVING:分组、去重后的视图,数据与底层单行数据不是一一对应的,无法定位要修改的具体行,因此无法操作。
四、综合动手实践:医院全角色视图落地
结合前面所有知识点,完成医院不同角色的视图落地,实现权限隔离与查询简化。
场景 1:导诊人员角色视图
需求:仅能查看科室信息、医生姓名、科室、职称,无法查看薪资、挂号费等敏感数据
实现 SQL:
CREATE VIEW v_guide_doc
AS
SELECT
b.emp_name 医生姓名,
c.dpt_name 所属科室,
b.title 职称,
c.location 科室位置
FROM his_emp b
LEFT JOIN his_dpt c ON b.dpt_code = c.dpt_code;
-- 给导诊角色授予视图查询权限,不授予基本表权限
GRANT SELECT ON v_guide_doc TO guide_role;
场景 2:科室主任角色视图
需求:仅能查看自己科室的医生信息、本科室的所有挂号记录
实现 SQL:
-- 普外科主任视图
CREATE VIEW v_wai01_head
AS
SELECT * FROM v_reg_detail
WHERE 所属科室 = '普外科'
WITH CHECK OPTION;
-- 授予查询权限
GRANT SELECT ON v_wai01_head TO surgery_head;
场景 3:财务人员角色视图
需求:查看各科室挂号收入统计、医生薪资统计,无修改权限
实现 SQL:
CREATE VIEW v_finance_sal_stat(科室名称, 医生人数, 薪资总额, 平均薪资)
AS
SELECT
c.dpt_name,
COUNT(b.emp_id),
SUM(b.sal),
AVG(b.sal)
FROM his_emp b
LEFT JOIN his_dpt c ON b.dpt_code = c.dpt_code
GROUP BY c.dpt_name;
-- 授予查询权限
GRANT SELECT ON v_finance_sal_stat TO finance_role;
五、核心总结
视图是不存储数据的虚拟表,本质是一条预定义的 SELECT 查询语句,类比为电脑的快捷方式,核心价值是简化查询、权限控制、提升数据独立性。
视图的核心管理操作:创建(
CREATE VIEW)、查看(\dv/pg_views)、修改(CREATE OR REPLACE/ALTER VIEW)、删除(DROP VIEW)。仅单表无聚合无分组的视图可执行增删改操作,
WITH CHECK OPTION可实现数据约束,防止越权操作。视图是数据库权限精细化管理的核心工具,企业级业务场景中,可通过视图实现不同角色的数据隔离,保障数据安全。
(注)