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;

注意:创建增量刷新的物化视图,必须:

  1. 创建物化视图中涉及表的物化视图日志。
  2. 在查询语句中,必须包含所有表的 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 视图名称;

猜你喜欢

转载自blog.csdn.net/Java_Fly1/article/details/124723252