视图
📄字数 4.9K
👁️阅读量 加载中...
数据库视图是虚拟表,并不直接存储数据,通过从一个或多个实际表或视图中动态生成数据,可用于简化复杂查询、增强数据的安全性以及提供更灵活的数据访问方式。视图本身是对数据库表的一种抽象层,它允许用户通过查询视图来访问和操作数据,而无需直接处理基础表中的具体细节。
数据库中可以使用视图的场景有:
- 多表联合查询、聚合函数、子查询与和复杂筛选条件。
- 隐藏敏感数据(密码、财务数据)、查询部分列或行的数据。
- 基表结构发生变化时,应用程序无需修改、数据模型变动时提供统一的接口。
- 不同数据源的数据整合到一个统一的虚拟表中,方便用户进行数据访问。
一、创建视图
1.1 语法格式
( SelectStmt::=
, joined_table::=
, alias_clause::=
)
1.2 参数说明
Cre_Rep
:视图创建语句。OR REPLACE
:指定视图存在则替换,用于更新视图定义。NOFORCE
:不强制创建或替换,默认。FORCE
:强制创建或替换。
IF NOT EXISTS
:创建视图时存在同名视图则忽略错误,不会再创建视图。sche_name
:模式名,模式名可不写,默认当前模式。view_name
:创建的视图名。opt_column_list
:用于指定视图中各字段名,当不指定时,字段名将从SELECT子句中抽取,若SELECT子句中的输出项目不是字段而是表达式,则视图字段名将由系统生成,视图创建者可根据实际情况选择是否指定视图字段名。对于视图中各字段名,需严格遵循数据库对象命名规则
。collable
:视图中各字段名。
view_opt
:视图可执行操作选项。WITH READ ONLY
:创建的视图是只读视图,不能进行更新、插入、删除操作。WITH CHECK OPTION
:可以进行插入和更新操作,插入或更新的数据必须仍能被视图的 WHERE 子句筛选,否则操作会失败。
opt_comment
:对视图进行注释。SCONST
:视图注释内容。
提示
- IF NOT EXISTS无法验证已有同名视图与当前创建视图结构一致,故在使用时请注意确认已有视图的实际定义,避免直接执行导致旧视图逻辑被意外保留。
1.3 示例
示例
创建名为student_view
的视图用于展示学生的基本信息
SQL
SQL> CREATE TABLE student_tab(st_no INT, st_name VARCHAR, st_sex VARCHAR, st_department VARCHAR);
SQL> INSERT INTO student_tab VALUES(20250401,'张三','男','学生');
SQL> CREATE VIEW student_view (id, name, sex, department) AS SELECT st_no, st_name, st_sex, st_department FROM student_tab;
SQL> SELECT *FROM student_view;
+----------+------+-----+------------+
| ID | NAME | SEX | DEPARTMENT |
+----------+------+-----+------------+
| 20250401 | 张三 | 男 | 学生 |
+----------+------+-----+------------+
-- 查询视图信息
SQL> SELECT view_name, define, option, create_time, valid FROM SYS_VIEWS WHERE view_name = 'student_view';
+--------------+--------+--------+--------------------------+-------+
| VIEW_NAME | DEFINE | OPTION | CREATE_TIME | VALID |
+--------------+--------+--------+--------------------------+-------+
| STUDENT_VIEW | <CLOB> | 0 | 2025-07-23 14:49:11.469 | T |
+--------------+--------+--------+--------------------------+-------+
-- 查看视图列信息
SQL> SELECT uc.* FROM SYS_VIEW_COLUMNS uc JOIN SYS_VIEWS ut ON uc.view_id=ut.view_id WHERE ut.view_name='student_view';
+-------+---------+------------+--------+-----------+-------+---------+----------+-----------+-----------+-----------+
| DB_ID | VIEW_ID | COL_NAME | COL_NO | TYPE_NAME | SCALE | VARYING | COMMENTS | RESERVED1 | RESERVED2 | RESERVED3 |
+-------+---------+------------+--------+-----------+-------+---------+----------+-----------+-----------+-----------+
| 1 | 1049847 | ID | 0 | INTEGER | -1 | F | <NULL> | <NULL> | <NULL> | <NULL> |
| 1 | 1049847 | NAME | 1 | CHAR | -1 | F | <NULL> | <NULL> | <NULL> | <NULL> |
| 1 | 1049847 | SEX | 2 | CHAR | -1 | F | <NULL> | <NULL> | <NULL> | <NULL> |
| 1 | 1049847 | DEPARTMENT | 3 | CHAR | -1 | F | <NULL> | <NULL> | <NULL> | <NULL> |
+-------+---------+------------+--------+-----------+-------+---------+----------+-----------+-----------+-----------+
示例
创建一个视图,将多个表通过内连接合并,查询最终结果
SQL
-- 存储用户基本信息
SQL> CREATE TABLE user_tab (id INT PRIMARY KEY, name VARCHAR(50), email VARCHAR(100));
-- 存储用户的订单信息
SQL> CREATE TABLE order_tab (order_id INT PRIMARY KEY, user_id INT, product VARCHAR(50), FOREIGN KEY (user_id) REFERENCES user_tab(id));
-- 存储订单的物流信息
SQL> CREATE TABLE logistics_tab (tracking_id INT PRIMARY KEY, order_id INT, status VARCHAR(20), FOREIGN KEY (order_id) REFERENCES order_tab(order_id));
-- 向 user_tab 插入用户数据
SQL> INSERT INTO user_tab (id, name, email) VALUES(1, 'Alice', 'alice@example.com'), (2, 'Bob', 'bob@example.com');
-- 向 order_tab 插入订单数据
SQL> INSERT INTO order_tab (order_id, user_id, product) VALUES(101, 1, 'Laptop'), (102, 1, 'Phone'), (103, 2, 'Tablet');
-- 向 logistics_tab 插入物流数据
SQL> INSERT INTO logistics_tab (tracking_id, order_id, status) VALUES(1001, 101, 'Shipped'), (1002, 102, 'Pending'), (1003, 103, 'Delivered');
SQL> CREATE VIEW alice_orders_with_tracking AS
SELECT
t1.id AS user_id,
t1.name,
t1.email,
t1.order_id AS t1_order_id, -- 来自 order_tab 的 order_id
logistics_tab.order_id AS logistics_tab_order_id, -- 来自 logistics_tab 的 order_id
t1.product,
logistics_tab.tracking_id,
logistics_tab.status
FROM (
(user_tab JOIN order_tab ON user_tab.id = order_tab.user_id) AS t1
JOIN logistics_tab ON t1.order_id = logistics_tab.order_id
)
WHERE t1.name = 'Alice' WITH CHECK OPTION COMMENT 'Alice的订单信息';
SQL> SELECT * FROM alice_orders_with_tracking;
+---------+-------+-------------------+-------------+------------------------+---------+-------------+---------+
| USER_ID | NAME | EMAIL | T1_ORDER_ID | LOGISTICS_TAB_ORDER_ID | PRODUCT | TRACKING_ID | STATUS |
+---------+-------+-------------------+-------------+------------------------+---------+-------------+---------+
| 1 | Alice | alice@example.com | 101 | 101 | Laptop | 1001 | Shipped |
| 1 | Alice | alice@example.com | 102 | 102 | Phone | 1002 | Pending |
+---------+-------+-------------------+-------------+------------------------+---------+-------------+---------+
示例
通过CREATE OR REPLACE 修改视图
SQL
SQL> CREATE OR REPLACE VIEW alice_orders_with_tracking AS SELECT * FROM user_tab JOIN order_tab ON user_tab.id = order_tab.user_id;
SQL> SELECT * FROM alice_orders_with_tracking;
+----+-------+-------------------+----------+---------+---------+
| ID | NAME | EMAIL | ORDER_ID | USER_ID | PRODUCT |
+----+-------+-------------------+----------+---------+---------+
| 1 | Alice | alice@example.com | 101 | 1 | Laptop |
| 1 | Alice | alice@example.com | 102 | 1 | Phone |
| 2 | Bob | bob@example.com | 103 | 2 | Tablet |
+----+-------+-------------------+----------+---------+---------+
示例
join table测试
SQL
SQL> CREATE OR REPLACE VIEW join_tab_view AS (user_tab t1 JOIN order_tab t2 ON t1.id = t2.user_id ) AS joins;
SQL> SELECT * FROM join_tab_view;
+----+-------+-------------------+----------+---------+---------+
| ID | NAME | EMAIL | ORDER_ID | USER_ID | PRODUCT |
+----+-------+-------------------+----------+---------+---------+
| 1 | Alice | alice@example.com | 101 | 1 | Laptop |
| 1 | Alice | alice@example.com | 102 | 1 | Phone |
| 2 | Bob | bob@example.com | 103 | 2 | Tablet |
+----+-------+-------------------+----------+---------+---------+
注意
对于表对象中包含用户自定义类型(UDT)、大对象类型、空间类型等,支持创建视图。
不支持使用本地临时表创建视图,但支持全局临时表创建视图。若要使用全局临时表,必须先启用参数support_global_tab
,请参阅系统配置参数support_global_tab
。
如果通过*
选择表的所有列,再向表中添加了新列,视图中不会包含新列。
关于视图的权限管理,具体请参考《权限管理》。
对于JOIN TABLE
:若连接的两个表中存在同名字段,将会创建视图失败。
二、删除视图
2.1 语法格式
2.2 参数说明
IF EXISTS
:删除不存在的视图时,忽略'视图不存在'的错误。sche_name
:模式名,模式名可不写,默认当前模式。view_name
:创建的视图名。RESTRICT
:删除视图时,只有在该视图及其对象没有被其他对象或模式对象依赖,才能成功删除。如果该视图被其他对象引用,数据库返回错误,拒绝删除操作。CASCADE
:如果该视图被其他对象(如其他视图或存储过程)引用,则级联删除这些依赖对象,同CASCADE CONSTRAINTS
。
2.3 示例
示例
强制删除视图alice_orders_with_tracking
sql
SQL> CREATE OR REPLACE PROCEDURE alice_view_pro AS
id_order int;
BEGIN
SELECT id INTO id_order FROM alice_orders_with_tracking WHERE id = 1;
SEND_MSG(id_order);
END;
/
SQL> DROP VIEW alice_orders_with_tracking;
Error: [E6006] 存在对视图JOIN_TAB_VIEW依赖的对象
SQL> DROP VIEW alice_orders_with_tracking CASCADE;
三、重编译视图
当依赖对象发生变化(如基表结构变更,包括基表删除、字段或表重命名、列删除等)时,数据库视图会因失效而无法正常工作,此时需通过重新编译恢复其可用性的操作。
3.1 语法格式
3.2 示例
SQL
-- 创建部门表
SQL> CREATE TABLE departments (dept_id INT PRIMARY KEY, dept_name VARCHAR2(50), dept_count BIGINT, dept_salary DOUBLE);
-- 创建视图
SQL> CREATE VIEW dep_view AS SELECT dept_id, dept_name FROM departments;
-- 强制删除表,导致视图失效
SQL> DROP TABLE departments CASCADE;
SQL> SELECT VALID FROM SYS_VIEWS WHERE view_name = 'dep_view';
+-------+
| VALID |
+-------+
| F |
+-------+
-- 重新创建departments,并对dep_view进行重编译,功能恢复
SQL> CREATE TABLE departments (dept_id INT PRIMARY KEY, dept_name VARCHAR2(50), dept_count BIGINT, dept_salary DOUBLE);
SQL> ALTER VIEW dep_view RECOMPILE;
SQL> SELECT VALID FROM SYS_VIEWS WHERE view_name = 'dep_view';
+-------+
| VALID |
+-------+
| T |
+-------+