oracle-视 图
什么是视图
- 视图是一种虚表。
- 视图建立在已有表的基础上, 视图赖以建立的这些表称为基表。
- 向视图提供数据内容的语句为
SELECT
语句, 可以将视图理解为存储起来的SELECT 语句
- 视图向用户提供基表数据的另一种表现形式
为什么使用视图
- 控制数据访问
- 简化查询
- 避免重复访问相同的数据
简单视图和复杂视图
特性 | 简单视图 | 复杂视图 |
---|---|---|
表的数量 | 一个 | 一个或多个 |
函数 | 没有 | 有 |
分组 | 没有 | 有 |
DML 操作 | 可以 | 有时可以 |
创建视图
- 在
CREATE VIEW
语句中嵌入子查询
CREATE [OR REPLACE] [FORCE|NOFORCE] VIEW 视图名称
[(alias[, alias]...)]
AS subquery
[WITH CHECK OPTION [CONSTRAINT 约束名称]]
[WITH READ ONLY [CONSTRAINT 约束名称]];
OR REPLACE :若所创建的试图已经存在,ORACLE 自动重建该视图;
FORCE :不管基表是否存在 ORACLE 都会自动创建该视图;
subquery :一条完整的 SELECT 语句,可以在该语句中定义别名;
WITH CHECK OPTION :插入或修改的数据行必须满足视图定义的约束;
WITH READ ONLY :该视图上不能进行任何 DML 操作。
- 子查询可以是复杂的 SELECT 语句
-- 创建视图empview
create or replace view empview
as
select employee_id emp_id,last_name name,department_name
from employees e,departments d
Where e.department_id = d.department_id
描述视图结构
DESCRIBE empvu80
- 创建视图时在子查询中给列定义别名
CREATE VIEW salvu50
AS SELECT employee_id ID_NUMBER, last_name NAME,
salary*12 ANN_SALARY
FROM employees
WHERE department_id = 50;
- 在选择视图中的列时应使用别名
select ID_NUMBER,NAME,ANN_SALARY from salvu50;
带检查约束的视图
需求:根据地址表(T_ADDRESS)创建视图 VIEW_ADDRESS2 ,内容为区域 ID
为 2 的记录。
-- 带检查约束的视图
create or replace view view_address2 as
select * from T_ADDRESS where areaid=2
with check option
执行下列更新语句:
-- 无法修改成功的语句,因为该视图的条件是areaid=2
update view_address2 set areaid=1 where id=4;
系统提示如下错误信息:
只读视图
如果我们创建一个视图,并不希望用户能对视图进行修改,那我们就需要创建视
图时指定 WITH READ ONLY
选项,这样创建的视图就是一个只读视图
create or replace view view_owners1 as
select * from T_OWNERS where ownertypeid=1
with read only;
修改后,再次执行 update 语句,会出现如下错误提示
带错误的视图
-- 视图来源的表根本不存在
-- 创建带错误的视图
create force view view_test as
select * from t_test;
复杂视图
所谓复杂视图,就是视图的 SQL 语句中,有聚合函数或多表关联查询。
--复杂视图-多表关联
create or replace view view_owners as
select ow.id 业主编号,ow.name 业主名称,ot.name 业主类型 from t_owners ow,t_ownertype ot
where ow.ownertypeid=ot.id;
那这个视图能不能去修改数据呢?
update view_owners set 业主名称='范小冰' where 业主编号=1;
可以修改成功。
再试一下下面的语句
update view_owners set 业主类型='普通居民' where 业主编号=1;
会发现,系统弹出错误提示:
-- 键保留表:把主键保留下来的那个表
什么叫键保留表呢?
键保留表是理解连接视图修改限制的一个基本概念。该表的主键列全部显示在视
图中,并且它们的值在视图中都是唯一且非空的。也就是说,表的键值在一个连
接视图中也是键值,那么就称这个表为键保留表。
在我们这个例子中,视图中存在两个表,业主表(T_OWNERS)和业主类型表
(T_OWNERTYPE), 其中 T_OWNERS 表就是键保留表,因为 T_OWNERS 的
主键也是作为视图的主键。键保留表的字段是可以更新的,而非键保留表是不能
更新的。
聚合统计的视图
聚合统计的视图不能进行修改
--聚合统计的复杂视图
create view view_accountsum as
select year,month,sum(money) money
from t_account
group by year,month
order by year,month;
查询视图的数据
--能修改吗?--答:不能的。
update view_accountsum set month='04' where year='2012' and month='03'
物化视图
什么是物化视图
视图是一个虚拟表(也可以认为是一条语句),基于它创建时指定的查询语
句返回的结果集。每次访问它都会导致这个查询语句被执行一次。为了避免每次
访问都执行这个查询,可以将这个查询结果集存储到一个物化视图(也叫实体化
视图)。
物化视图与普通的视图相比的区别是物化视图是建立的副本,它类似于一张
表,需要占用存储空间。而对一个物化视图查询的执行效率与查询一个表是一样
的。
创建物化视图语法
CREATE METERIALIZED VIEW view_name
[BUILD IMMEDIATE | BUILD DEFERRED ]
REFRESH [FAST|COMPLETE|FORCE]
[
ON [COMMIT |DEMAND ] | START WITH (start_time) NEXT
(next_time)
]
AS
subquery
BUILD IMMEDIATE 是在创建物化视图的时候就生成数据
BUILD DEFERRED 则在创建时不生成数据,以后根据需要再生成数据。
默认为 BUILD IMMEDIATE。
刷新(REFRESH):指当基表发生了 DML 操作后,物化视图何时采用哪种
方式和基表进行同步。
REFRESH 后跟着指定的刷新方法有三种:FAST、COMPLETE、FORCE。FAST
刷新采用增量刷新,只刷新自上次刷新以后进行的修改。COMPLETE 刷新对整
个物化视图进行完全的刷新。如果选择 FORCE 方式,则 Oracle 在刷新时会去判
断是否可以进行快速刷新,如果可以则采用 FAST 方式,否则采用 COMPLETE
的方式。FORCE 是默认的方式。
刷新的模式有两种:ON DEMAND 和 ON COMMIT。ON DEMAND 指需要
手动刷新物化视图(默认)。ON COMMIT 指在基表发生 COMMIT 操作时自动
刷新
案例
1.创建手动刷新的物化视图
--COMPLETE 完全刷新
--FAST 增量更新
--FORCE 自动选择
--ON COMMIT 在基表做提交操作是刷新物化视图
--ON DEMAND 手动刷新
--创建手动刷新的物化视图
create materialized view view_address1 as
select ad.id,ad.name,ar.name arname from t_address ad,t_area ar
where ad.areaid=ar.id
执行语句成功后,可以在Materialized views中看到新建的视图,并且在对应的表空间创建了一个表
删除物化视图
drop materialized view 视图名称;
查询物化视图
--查询物化视图
select * from mv_address1
--创建时不生成数据的物化视图
create materialized view mv_address3
build deferred
refresh
on commit
as
select ad.id,ad.name,ar.name arname from t_address ad,t_area ar
where ad.areaid=ar.id
insert into T_ADDRESS VALUES(12,'西7旗',2,2);
commit;
-- 使用sql语句进行查询,会发现新插入的语句并没有出现在物化视图中
--查询物化视图
select * from mv_address3
-- 我们需要通过下面的语句(PL/SQL),手动刷新物化视图:
--第一次必须手动执行刷新,
begin
DBMS_MVIEW.refresh('MV_ADDRESS3','C');
end;
或者通过下面的命令手动刷新物化视图:
EXEC DBMS_MVIEW.refresh('MV_ADDRESS3','C');
-- 注意:此语句需要在命令窗口中执行。
-- 执行此命令后再次查询物化视图,就可以查询到最新的数据了。
DBMS_MVIEW.refresh 实际上是系统内置的存储过程
在pl/sql中打开命令窗口
创建自动刷新的物化视图
语句如下:
--创建自动刷新的物化视图 -基表发生commit操作,自动刷新物化视图
create materialized view mv_address2
refresh
on commit
as
select ad.id,ad.name,ar.name arname from t_address ad,t_area ar
where ad.areaid=ar.id
创建此物化视图后,当 T_ADDRESS 表发生变化时,MV_ADDRESS2 自动跟着
改变。
--向基表插入数据
insert into T_ADDRESS VALUES(10,'西5旗',2,2);
commit;
--查询物化视图
select * from mv_address2;
创建时不生成数据的物化视图
-- 创建时不生成数据的物化视图
create materialized view mv_address3
build deferred
refresh
on commit
as
select ad.id,ad.name,ar.name arname from t_address ad,t_area ar
where ad.areaid=ar.id;
--查询物化视图
select * from mv_address3
insert into T_ADDRESS VALUES(12,'西7旗',2,2);
commit;
-- 由于我们创建时指定的 on commit ,所以在修改数据后能立刻看到最新数据,无须
--再次执行 refresh
--第一次必须手动执行刷新,
begin
DBMS_MVIEW.refresh('MV_ADDRESS3','C');
end;
创建增量刷新的物化视图
如果创建增量刷新的物化视图,必须首先创建物化视图日志
--.创建增量刷新的物化视图
--前提是必须创建物化视图日志 :记录基表发生了哪些变化,用这些记录去更新物化视图
create materialized view log on t_address with rowid;
create materialized view log on t_area with rowid;
创建的物化视图日志名称为 MLOG$_表名称
创建物化视图
--创建物化视图中的语句中,必须有基表的ROWID
create materialized view mv_address4
refresh fast
as
select ad.rowid adrowid,ar.rowid arrowid, ad.id,ad.name,ar.name arname from t_address ad,t_area ar
where ad.areaid=ar.id;
注意:创建增量刷新的物化视图,必须:
- 创建物化视图中涉及表的物化视图日志。
- 在查询语句中,必须包含所有表的 rowid ( 以 rowid 方式建立物化视图日志 )
当我们向地址表插入数据后,物化视图日志的内容:
--插入数据
insert into T_ADDRESS VALUES(14,'西9旗',2,2);
SNAPTIME$$
:用于表示刷新时间。
DMLTYPE$$
:用于表示 DML 操作类型,I 表示 INSERT,D 表示 DELETE,U表示 UPDATE。
OLD_NEW$$
:用于表示这个值是新值还是旧值。N(EW)表示新值,O(LD)
表示旧值,U 表示 UPDATE 操作。
CHANGE_VECTOR$$
:表示修改矢量,用来表示被修改的是哪个或哪几个字段。
此列是 RAW 类型,其实 Oracle 采用的方式就是用每个 BIT 位去映射一个列。
插入操作显示为:FE, 删除显示为:OO 更新操作则根据更新字段的位置而显示
不同的值。
当我们手动刷新物化视图后,物化视图日志被清空,物化视图更新。
begin
DBMS_MVIEW.refresh('MV_ADDRESS4','C');
end;
修改视图
- 使用
CREATE OR REPLACE VIEW
子句修改视图 - CREATE VIEW 子句中各列的别名应和子查询中各列相对应
CREATE OR REPLACE VIEW empvu80
(id_number, name, sal, department_id)
AS SELECT employee_id, first_name || ' ' || last_name,
salary, department_id
FROM employees
WHERE department_id = 80;
视图中使用DML的规定
- 可以在简单视图中执行 DML 操作
- 当视图定义中包含以下元素之一时不能使用
delete:
组函数
GROUP BY 子句
DISTINCT 关键字
ROWNUM 伪列
create or replace view sal_view
as select
avg(salary) avg_sal from employees
group by department_id
- 当视图定义中包含以下元素之一时不能使用
update
:
组函数
GROUP BY子句
DISTINCT 关键字
ROWNUM 伪列
列的定义为表达式
- 当视图定义中包含以下元素之一时不能使
insert:
组函数
GROUP BY 子句
DISTINCT 关键字
ROWNUM 伪列
列的定义为表达式
表中非空的列在视图定义中未包括
屏蔽 DML 操作
- 可以使用
WITH READ ONLY
选项屏蔽对视图的DML 操作 - 任何
DML
操作都会返回一个Oracle server
错误
CREATE OR REPLACE VIEW empvu10
(employee_number, employee_name, job_title)
AS SELECT employee_id, last_name, job_id
FROM employees
WHERE department_id = 10
WITH READ ONLY;
删除视图
删除视图只是删除视图的定义,并不会删除基表的数据
drop view 视图名称;